基本的思路是这样的:在服务器端,有两个机器,一个对外开启 TCP 监听,然后把监听到的请求内容送到后面的另外一台,或者多台轮询机器上,内网之间使用 UDP,然后等待业务逻辑机器处理完成,这个地方可以做成异步的,然后再返回到用户。
即是这样: client <-TCP-> server_front <-UDP-> server_back
下面来看代码,首先是 server_front 的 demo
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include "struct.h"
int main() {
int tcpfd = socket(AF_INET, SOCK_STREAM, 0);
if (tcpfd == -1) {
perror("tcpfd socket");
return -1;
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(38080);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(tcpfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
perror("tcpfd bind");
return -1;
}
if (listen(tcpfd, 10) == -1) {
perror("tcpfd listen");
return -1;
}
// udp
int udpfd = socket(AF_INET, SOCK_DGRAM, 0);
if (udpfd == -1) {
perror("udpfd socket");
return -1;
}
struct sockaddr_in udp_serv_addr;
memset(&udp_serv_addr, 0, sizeof(udp_serv_addr));
udp_serv_addr.sin_family = AF_INET;
udp_serv_addr.sin_port = htons(8080);
if (inet_pton(AF_INET, "10.1.164.18", &udp_serv_addr.sin_addr) <= 0) {
perror("udpfd inet pton");
return -1;
}
while (1) {
int tcp_conn_fd = accept(tcpfd, NULL, NULL);
if (tcp_conn_fd == -1) {
perror("tcpfd accept");
return -1;
}
char buff[2048];
memset(buff, 0, sizeof(buff));
int recvn = recv(tcp_conn_fd, buff, sizeof(buff), 0);
if (recvn == -1) {
perror("tcpfd recv");
return -1;
}
printf("recv: [%s]\n", buff);
//char html_resp[] = "HTTP/1.1 200 OK\r\n\r\ntcp udp mix";
UDP_MSG udp_msg;
memset(&udp_msg, 0, sizeof(udp_msg));
strcpy(udp_msg.str1, "HTTP/1.1 200 OK\r\n\r\n");
strcpy(udp_msg.str2, "send to udp for cat");
if (sendto(udpfd, &udp_msg, sizeof(udp_msg), 0, (struct sockaddr*)&udp_serv_addr, sizeof(udp_serv_addr)) == -1) {
perror("udp send to");
return -1;
}
if (recvfrom(udpfd, &udp_msg, sizeof(udp_msg), 0, NULL, NULL) == -1) {
perror("udp recv from");
return -1;
}
if (send(tcp_conn_fd, udp_msg.cat, strlen(udp_msg.cat), 0) == -1) {
perror("tcp send");
return -1;
}
close(tcp_conn_fd);
}
close(tcpfd);
return 0;
}
然后是内部的报文格式 struct.h
#ifndef STRUCT_H
#define STRUCT_H
typedef struct _UDP_MSG {
int add1;
int add2;
int sum;
char str1[128];
char str2[128];
char cat[256];
} UDP_MSG;
#endif /* STRUCT_H */
然后是后端的业务逻辑服务器
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include "struct.h"
#define MAX_LINE 1024
#define SERV_PORT 8080
int udp_serv();
int main() {
return udp_serv();
}
int udp_serv() {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket");
return -1;
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(SERV_PORT);
if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
perror("bind");
return -1;
}
while (1) {
struct sockaddr_in cli_addr;
memset(&cli_addr, 0, sizeof(cli_addr));
UDP_MSG msg;
memset(&msg, 0, sizeof(msg));
socklen_t cli_addr_len = sizeof(cli_addr);
recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr*)&cli_addr, &cli_addr_len);
msg.sum = msg.add1 + msg.add2;
strcpy(msg.cat, msg.str1);
strcat(msg.cat, msg.str2);
printf("msg.add1 is: %d\n", msg.add1);
printf("msg.add2 is: %d\n", msg.add2);
printf("msg.sum is: %d\n", msg.sum);
printf("msg.str1 is: %s\n", msg.str1);
printf("msg.str2 is: %s\n", msg.str2);
printf("msg.cat is: %s\n", msg.cat);
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr*)&cli_addr, cli_addr_len);
}
return 0;
}
编译一下,就可以测试了
$ wget http://localhost:38080/123 && nl 123
--16:05:03-- http://localhost:38080/123
=> `123.2'
Resolving localhost... 127.0.0.1
Connecting to localhost|127.0.0.1|:38080... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified
[<=> ] 19 --.--K/s
16:05:03 (3.62 MB/s) - `123.2' saved [19]
1 send to udp for cat
期间,server_front 的输出应该是这样的
recv: [GET /123 HTTP/1.0 User-Agent: Wget/1.10.2 Accept: */* Host: localhost:38080 Connection: Keep-Alive ]
后台业务逻辑服务器的输出应该是这样的
msg.add1 is: 0 msg.add2 is: 0 msg.sum is: 0 msg.str1 is: HTTP/1.1 200 OK msg.str2 is: send to udp for cat msg.cat is: HTTP/1.1 200 OK send to udp for cat