zoukankan      html  css  js  c++  java
  • Linux 套接字编程

    第五章的内容,实现一个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
    ");
     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!
    ");
     57                         continue;
     58                 }
     59                 if (fork() == 0) {
     60                         close(server_fd);
     61                         printf("child process start pid(%d)
    ", getpid());
     62 
     63                         echo(client_fd);
     64 
     65                         printf("child process exit  pid(%d)
    ", 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
    ", 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_RESTART
    104         act.sa_flags |= SA_RESTART;
    105         printf("SA_RESTART
    ");
    106 #endif
    107         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 256
    
    void 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
    ");
                            break;
                    } else {
                            printf("1st write ok
    ");
                    }
    
                    sleep(1);
    
                    if ((writen = write(fd, "(test)", strlen("(test)") + 1)) < 0) {
                            printf("2nd write error
    ");
                            break;
                    } else {
                            printf("2nd write ok
    ");
                    }
    
                    sleep(1);
    
                    if ((readn = read(fd, recv_buf, BUF_SIZE)) < 0) {
                            printf("read error
    ");
                            break;
                    } else if (readn == 0) {
                            printf("read EOF
    ");
                            break;
                    }
                    fputs(recv_buf, stdout);
            }
            printf("client exit
    ");
    }
  • 相关阅读:
    Masterha-manager避免自动关闭的方法
    MHA自动切换流程
    vue 使用keep-alive缓存tab切换组件,保持每个组件滚动条位置
    el-select 输入下拉搜索,匹配不到数据时也保留输入值,同时input获取焦点时保留其value值
    尝试 React16、React-router4 实现根据动态菜单生成按需加载的路由
    vue iscroll5滚动条组件
    vue项目中 axios请求拦截器与取消pending请求功能
    jquery编写的简单日历
    手机访问电脑wampServer本地环境页面
    ajax在ie下返回未定义解决方案
  • 原文地址:https://www.cnblogs.com/lailailai/p/3917738.html
Copyright © 2011-2022 走看看