UNIX TCP回射服务器/客户端(2)

程序简介:这是一个传统的多进程服务器模型。当一个客户端连接上服务器时,服务器就产生一个子进程来与客户端进行通信。这种通信机制不但效率低,而且最大连接数会受到系统的最大子进程数的限制。但是它的实现相对简单,所以在早期的UNIX系统中比较流行。

上代码:

#include "my_unp.h" 
 
void str_echo(int sockfd) 

    ssize_t n; 
    char buf[MAXLINE]; 
 
again: 
    //从套接字中读取数据,写到buffer中去 
    //再将buffer中的数据写到套接字中去 
    while( (n=read(sockfd, buf, MAXLINE)) > 0 ) 
        Writen(sockfd, buf, n); 
 
    //由于信号中断,没写或读成功任何数据 
    if( n<0 && errno==EINTR ) 
        goto again; 
    else if( n < 0 ) 
        error_quit("str_echo: read error"); 

 
//捕获并处理子进程的SIGCHLD信号 
void sig_child(int signo) 

    pid_t pid; 
    int stat; 
    while( (pid=waitpid(-1, &stat, WNOHANG)) > 0 ) 
        printf("child %d terminated\n", pid); 
    return; 

 
int main(void) 

    int listenfd, connfd; 
    pid_t childpid; 
    socklen_t clilen; 
    char buff[MAXLINE]; 
    struct sockaddr_in cliaddr, servaddr; 
 
    //创建用于TCP协议的套接字 
    listenfd = Socket(AF_INET, SOCK_STREAM, 0); 
    memset(&servaddr, 0, sizeof(servaddr)); 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    servaddr.sin_port = htons(SERV_PORT); 
 
    //把socket和socket地址结构联系起来   
    Bind(listenfd, (SA*)&servaddr, sizeof(servaddr)); 
    //开始监听LISTENQ端口 
    Listen(listenfd, LISTENQ); 
 
    //处理SIGCHLD信号,防止子进程变成僵死进程 
    Signal(SIGCHLD, sig_child); 
 
    while(1) 
    { 
        clilen = sizeof(cliaddr); 
 
        //接受一个来自客户端的连接   
        //如果没有连接请求,就使程序睡眠,直到有连接请求--这是accept函数的特性   
        //accept函数返回一个描述符,这个socket(connfd)用于同连接到的客户的通信 
        connfd = accept(listenfd, (SA*)&cliaddr, &clilen); 
 
        if( connfd < 0 ) 
        { 
            //accetp()是慢系统调用,在信号产生时会中断其调用, 
            //并将errno变量设置为EINTR,此时应重新调用 
            if( errno == EINTR ) 
                continue; 
            else 
                error_quit("accept error"); 
        } 
 
        //产生一个子进程,让它处理与(某个客户端的)通信 
        childpid = Fork(); 
        if( childpid == 0 ) 
        { 
            Close(listenfd); 
            str_echo(connfd); 
            return 0; 
        } 
        //输出客户端的IP地址与端口号,还有处理(子)进程的PID 
        printf("connection from %s, port %d. process with clild %d\n",   
            Inet_ntop(AF_INET, (void*)&cliaddr.sin_addr, buff, sizeof(buff)),   
            ntohs(cliaddr.sin_port), childpid); 
        //与客户端的通信由子进程来处理,所以关闭此套接字 
        Close(connfd); 
    } 
    return 0; 

与其配套的客户端在这里:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/705b6d211bf1cc988c7ad0b9b8966423.html