用TCP/TP进行网际互连(6) ———— 利用I/O复用完成单进程并发服务器的处理

来源:互联网 发布:软件性质 编辑:程序博客网 时间:2024/05/08 02:44

用TCP/TP进行网际互连(6)

———— 利用I/O复用完成单进程并发服务器的处理

1、实现原理

1)创建套接字并将其绑定到这个服务的熟知端口上,将该套接字加到一个表中,该表中的项是可以进行I/O的描述符。
2)使用select在已经有的套接字上等待I/O。
3)如果最初的套接字准备就绪,使用accept获得下一个连接,并将这个新的套接字加入到表中,该表中的项是可以进行I/O的描述符。
4)如果最初的套接字以外的套接字就绪,就使用recv或read获得下一个请求,构造响应,用send或者write将响应发回给客户。
5)继续按照以上的步骤2进行处理。

2、代码实现

  • 服务器:
#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in.h>#include <unistd.h>#include <string.h>#include <stdio.h>#include <errno.h>#define PORT 6000#define LISTENQ 20#define BUFFSIZE 4096#define FILE_NAME_MAX_SIZE 512int     echo(int sc){    //process_conn_server(sc);      /*处理连接*/            ssize_t size = 0;            char buffer[1024];                          /*数据的缓冲区*/                  size = read(sc, buffer, 1024);          /*从套接字中读取数据放到                                                   缓冲区buffer中*/                write(sc, buffer, strlen(buffer)+1);/*发给客户端*/            return size;}int passiveTCP (const char*service){    //Create socket    int sockfd,connfd;    struct sockaddr_in svraddr,clientaddr;    bzero(&svraddr,sizeof(svraddr));    svraddr.sin_family=AF_INET;    svraddr.sin_addr.s_addr=htonl(INADDR_ANY);    svraddr.sin_port=htons(PORT);    sockfd=socket(AF_INET,SOCK_STREAM,0);    if(sockfd<0)    {        perror("socket");        exit(1);    }    //bind      if(bind(sockfd,(struct sockaddr*)&svraddr,sizeof(svraddr))<0)    {        perror("bind");        exit(1);    }    //listen    if(listen(sockfd,LISTENQ)<0)    {        perror("listen");        exit(1);    }    return sockfd;}int main(int argc, char *argv[]){             char    *service = "echo";/* service name or port number*/    struct sockaddr_in fsin;    /* the from address of a client */    int msock;      /* master server socket     */    fd_set  rfds;           /* read file descriptor set */    fd_set  afds;           /* active file descriptor set   */    unsigned int    alen;      /* from-address length   */    int fd, nfds;    msock = passiveTCP(service);    nfds = getdtablesize();    FD_ZERO(&afds);    FD_SET(msock, &afds);    while (1) {      memcpy(&rfds, &afds, sizeof(rfds));      if (select(nfds, &rfds, (fd_set *)0, (fd_set *)0,(struct timeval *)0) < 0)        //errexit("select: %s\n", strerror(errno));        printf("select error");    if (FD_ISSET(msock, &rfds)) {        int ssock;        alen = sizeof(fsin);        ssock = accept(msock, (struct sockaddr *)&fsin,&alen);        if (ssock < 0)        //errexit("accept: %s\n",strerror(errno));        printf("accept error");        FD_SET(ssock, &afds);        }    for (fd=0; fd<nfds; ++fd)        if (fd != msock && FD_ISSET(fd, &rfds))            if (echo(fd) == 0) {                close(fd);                FD_CLR(fd, &afds);            }}}
  • 客户端
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <arpa/inet.h>#define PORT 6000                               /*侦听端口地址*/#define IP "127.0.0.1"                              /*服务器IP地址*/int main(int argc, char *argv[]){    int s;                                      /*s为socket描述符*/    struct sockaddr_in server_addr;         /*服务器地址结构*/    s = socket(AF_INET, SOCK_STREAM, 0);        /*建立一个流式套接字 */    if(s < 0){                                  /*出错*/        printf("socket error\n");        return -1;    }    /*设置服务器地址*/    bzero(&server_addr, sizeof(server_addr));   /*清零*/    server_addr.sin_family = AF_INET;                   /*协议族*/    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);    /*本地地址*/    server_addr.sin_port = htons(PORT);             /*服务器端口*/    /*将用户输入的字符串类型的IP地址转为整型*/    inet_pton(AF_INET, IP, &server_addr.sin_addr);    /*连接服务器*/    connect(s, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));    //process_conn_client(s);                       /*客户端处理过程*/    ssize_t size = 0;    char buffer[1024];                          /*数据的缓冲区*/    for(;;){                                    /*循环处理过程*/        /*从标准输入中读取数据放到缓冲区buffer中*/        size = read(0, buffer, 1024);        if(size > 0){                           /*读到数据*/            write(s, buffer, size);             /*发送给服务器*/            size = read(s, buffer, 1024);       /*从服务器读取数据*/            write(1, buffer, size);             /*写到标准输出*/        }    }    close(s);                                   /*关闭连接*/    return 0;}

3、运行效果

  • 服务器:
    这里写图片描述

  • 打开三个客户端同时连接:
    这里写图片描述
    可以看到,服务器可以对这三个客户端并发提供服务。

附上我的实验代码,有兴趣可以拿来看一下:
https://github.com/KevinBetterQ/Network-programming/tree/master/select

阅读全文
1 0
原创粉丝点击