基本的思路是这样的:在服务器端,有两个机器,一个对外开启 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