在c

时间:2018-02-04 16:12:54

标签: c select tcp server

我有一个小问题,实际上我必须让两个客户端与我的并发服务器进行通信(执行不同的功能),

我发现我可以使用select解决这个问题,但如果我尝试在代码中实现它会给我一个分段错误,有人可以帮助我吗?

我说过,在单个客户端之前是一个寓言,现在不幸的是实现了选择,我已经破坏了一切,

我应该修复这个问题,你可以用select()创建并发服务器吗? 你能告诉我这段代码的错误吗?

int main (int argc , char *argv[])
{
 int list_fd,conn_fd;
 int i,j;
 struct sockaddr_in serv_add,client;
 char buffer [1024];
 socklen_t len;
 time_t timeval;
 char fd_open[FD_SETSIZE];
 pid_t pid;
 int logging = 1;
 char swi;
 fd_set fset;
 int max_fd = 0;
 int waiting = 0;
 int compat = 0;

 sqlite3 *db;
 sqlite3_open("Prova.db", &db);

    start2();
    start3();

    printf("ServerREP Avviato \n");

    if ( ( list_fd = socket(AF_INET, SOCK_STREAM, 0) ) < 0 ) {
        perror("socket");
        exit(1);
    }

    if (setsockopt(list_fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0)
        perror("setsockopt(SO_REUSEADDR) failed");

  memset((void *)&serv_add, 0, sizeof(serv_add));   /* clear server address */
  serv_add.sin_family      = AF_INET;
  serv_add.sin_port        = htons(SERVERS_PORT2);
  serv_add.sin_addr.s_addr = inet_addr(SERVERS_IP2);


    if ( bind(list_fd, (struct sockaddr *) &serv_add, sizeof(serv_add)) < 0 ) {
       perror("bind");
        exit(1);
    }

    if ( listen(list_fd, 1024) < 0 ) {
        perror("listen");
        exit(1);
    }

    /* initialize all needed variables */
    memset(fd_open, 0, FD_SETSIZE);   /* clear array of open files */
    max_fd = list_fd;                 /* maximum now is listening socket */
    fd_open[max_fd] = 1;

    //max_fd = max(conn_fd, sockMED);
        while (1) { 
            FD_ZERO(&fset);
            FD_SET(conn_fd, &fset);
            FD_SET(sockMED, &fset);
            len = sizeof(client);

            if(select(max_fd + 1, &fset, NULL, NULL, NULL) < 0){exit(1);}

            if(FD_ISSET(conn_fd, &fset))
            { 
                if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len)) <0 )
                perror("accept error"); 
                exit(-1); 
            } 
         /* fork to handle connection */ 
            if ( (pid = fork()) < 0 ){      
                perror("fork error"); 
                exit(-1); 
            } 
            if (pid == 0) {                 /* child */ 
                close(list_fd);
                close(sockMED); 
                Menu_2(db,conn_fd);
                close(conn_fd); 
                exit(0); 
            } else {                        /* parent */ 
                close(conn_fd); 
        } 
        if(FD_ISSET(sockMED, &fset))
        MenuMED(db,sockMED);
        FD_CLR(conn_fd, &fset);
        FD_CLR(sockMED, &fset);
    } 

    sqlite3_close(db); 
    exit(0); 
} 

1 个答案:

答案 0 :(得分:1)

我无法理解您在此处尝试使用select的原因,以及为什么要使用fork让孩子处理已接受的连接套接字,以及select

常见设计是:

  • 多处理服务器:

    父进程设置侦听套接字并在等待实际连接时使用accept进行循环。然后它会让一个孩子处理新接受的连接,然后简单地等待下一个连接。

  • 多线程服务器:

    前一个版本的变体。主线程启动一个新线程来处理新接受的连接,而不是分支新进程。

  • 异步服务器:

    服务器设置fd_set以了解哪些套接字需要处理。最初,仅设置侦听套接字。然后主循环是(伪代码:

    loop on select
      if the listening socket is present in read ready sockets, accept the pending connection and add is to the `fd_set`, then return to loop
      if another socket is present in read ready socket
        read from it
        if a zero read (closed by peer), close the socket and remove it from the `fd_set`
        else process the request and return to loop
    

    这里的难点在于处理需要很长时间,整个过程被阻止,处理涉及发送大量数据,你也必须使用select作为发送部分......