首页 > 代码库 > Linux 套接字编程 - TCP连接基础
Linux 套接字编程 - TCP连接基础
第五章的内容,实现一个echo服务器和对应的客户端,主要收获:
0. TCP socket编程主要基本步骤
1. SIGCHLD信号含义(子进程退出时向父进程发送,提醒父进程对其状态信息进行一个获取),waitpid 和 wait在使用上的差异,前者可以配置参数设定为非阻塞方式调用,更加灵活。
2. 信号处理函数与其过程(尤其是信号发生后不列队这个性质),相同的信号多次发生(间隔非常接近的话)可能仅会调用一次信号处理函数
3. 信号处理对慢系统(阻塞)调用如accept等的影响(如果信号处理设置时没有置SA_RESTART),accept被中断后直接返回EINTR,而不是一个合法的socket fd,所以对一些调用的错误值检测并不是杞人忧天
4. 僵尸进程,只要父进程调用了wait*函数获取了已死子进程的状态信息后,它就消失了。但如果父进程产生了超多子进程,而他们有很快的死掉,然后父进程也不调用wait*函数,那么会使得pid号不够用
服务端程序:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #include <unistd.h> 6 #include <signal.h> 7 8 #include <sys/socket.h> 9 #include <arpa/inet.h> 10 #include <netinet/in.h> 11 12 13 #define SOCKET_BACKLOG 100 14 #define SERVER_PORT 1234 15 #define BUF_SIZE 256 16 17 void echo(int fd); 18 19 void setup_signal_handler(); 20 21 int main() { 22 /* setup SIGCHLD handler */ 23 setup_signal_handler(); 24 25 /* define socket address */ 26 struct sockaddr_in server = {0}; 27 server.sin_family = AF_INET; 28 server.sin_port = htons( SERVER_PORT ); 29 30 31 /* define socket file descriptor */ 32 int server_fd = socket(AF_INET, SOCK_STREAM, 0); 33 34 /* bind socket file descriptor to the socket address */ 35 bind(server_fd, (struct sockaddr *)&server, sizeof(server)); 36 37 /* listen on this socket file descriptor */ 38 listen( server_fd, SOCKET_BACKLOG ); 39 40 /* define socket struct/file descriptor used to present remote peer(client) */ 41 struct sockaddr_in client = {0}; 42 int client_fd; 43 int client_sockaddr_len = 0; 44 45 /* application send buffer */ 46 char buffer[BUF_SIZE]; 47 48 while (1) { 49 printf("server ready to accept\n"); 50 client_fd = accept(server_fd, (struct sockaddr *)&client, &client_sockaddr_len); 51 if (client_fd < 0) { 52 /* if SA_RESTART is not set in setup_signal_handler and 53 * then when process is interrupted by SIGCHLD 54 * the accept() will return EINTR instead of a valid socket fd 55 */ 56 printf("server accept error!\n"); 57 continue; 58 } 59 if (fork() == 0) { 60 close(server_fd); 61 printf("child process start pid(%d)\n", getpid()); 62 63 echo(client_fd); 64 65 printf("child process exit pid(%d)\n", getpid()); 66 exit(0); 67 } 68 close(client_fd); 69 } 70 71 return 0; 72 } 73 74 void echo(int fd) { 75 int n; 76 char buffer[BUF_SIZE]; 77 while ((n = read(fd, buffer, BUF_SIZE)) > 0) { 78 write(fd, buffer, n); 79 } 80 } 81 82 void signal_child_handler(int signo) { 83 pid_t pid; 84 int stat; 85 86 /* pid = wait(&stat); 87 * signal is not queued, many child process exits 88 * may just cause one signal handle process 89 * so we should use waitpid() in a row instead of a single wait() 90 * to collect child process information 91 */ 92 while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) { 93 printf("child process pid(%d) terminated\n", pid); 94 } 95 } 96 97 void setup_signal_handler() { 98 struct sigaction act, old_act; 99 100 act.sa_handler = signal_child_handler;101 sigemptyset(&act.sa_mask);102 act.sa_flags = 0;103 #ifdef SA_RESTART104 act.sa_flags |= SA_RESTART;105 printf("SA_RESTART\n");106 #endif107 if (sigaction(SIGCHLD, &act, &old_act) < 0) {108 printf("setup SIGCHLD Failed.");109 }110 }
客户端程序:
#include <unistd.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#define SERVER_PORT 1234#define SERVER_IP "127.0.0.1"#define BUF_SIZE 256void send_echo(FILE* fp, int fd);int main() { int sockfd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in server_addr = {0}; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr); connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); send_echo(stdin, sockfd); return 0;}void send_echo(FILE* fp, int fd) { char send_buf[BUF_SIZE] = {0}; char recv_buf[BUF_SIZE] = {0}; int readn = 0; int writen = 0; while(fgets(send_buf, BUF_SIZE, fp) != NULL) { if ((writen = write(fd, send_buf, strlen(send_buf) + 1)) < 0) { printf("1st write error\n"); break; } else { printf("1st write ok\n"); } sleep(1); if ((writen = write(fd, "(test)", strlen("(test)") + 1)) < 0) { printf("2nd write error\n"); break; } else { printf("2nd write ok\n"); } sleep(1); if ((readn = read(fd, recv_buf, BUF_SIZE)) < 0) { printf("read error\n"); break; } else if (readn == 0) { printf("read EOF\n"); break; } fputs(recv_buf, stdout); } printf("client exit\n");}
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。