Chinaunix

标题: select实现的回射服务器 [打印本页]

作者: cgp2001    时间: 2009-04-24 11:05
标题: select实现的回射服务器
找了一圈,觉得发在这个版块最合适。
我按照unix网络编程中的步骤以select实现了一个回射服务器,可是当只有一个连接的时候,正常工作,当第二个以上的连接连入时,客户端输入时,会阻塞在select函数,这时在第一个客户输入时,第二个客户的输入才会从服务器回射,不知道为什么,请高手指导。

下面是服务器和客户端的代码,运行时,注意修改IP.


serv.c

#define SERV_PORT 9877
#include "sys/select.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "string.h"
#include "stdio.h"
int main()
{
        int skt = socket(AF_INET,SOCK_STREAM,0);
        struct sockaddr_in servaddr;
        servaddr.sin_port = htons(SERV_PORT);
        servaddr.sin_family = AF_INET;
        inet_pton(AF_INET,"192.168.85.128",&servaddr.sin_addr);
        bind(skt,(struct sockaddr*)&servaddr,sizeof(servaddr));
        listen(skt,1024);
        int client[FD_SETSIZE],i;
        for(i=0;i<FD_SETSIZE;++i)
                client = -1;
        fd_set set,allset;
        FD_ZERO(&allset);
        FD_SET(skt,&allset);
        int stdeof = 0;
        int maxfd = skt ;
        int maxi = -1;

        for(;;)
        {
                set=allset;
                int nready = select(maxfd+1,&set,NULL,NULL,NULL);
                if(FD_ISSET(skt,&set))
                {
                        int connfd = accept(skt,NULL,NULL);
                        printf("new connectio:%d\n",connfd);
                        for(i=0;i<FD_SETSIZE;++i)
                                if(client<0)
                                {
                                        client = connfd;
                                        break;
                                }
                        FD_SET(connfd,&allset);
                        if(connfd > maxfd )
                                maxfd = connfd;
                        if( i>maxi )
                                maxi = i;
                        if(--nready<=0)
                                continue;
                }
                for(i=0;i<=maxi;++i)
                {
                        if(client<0)
                                continue;
                        if(FD_ISSET(client,&set))
                        {
                                int n;
                                char line[10240];
                                if((n=read(client,line,sizeof(line))) == 0)
                                {
                                        close(client);
                                        FD_CLR(client,&allset);
                                        client = -1;
                                }
                                else
                                        write(client,line,strlen(line));
                        }
                        if(--nready<=0)
                                break;
                }
        }
}


client.c

#include "sys/socket.h"
#include "netinet/in.h"
#include "stdio.h"
#include "string.h"
int main(int argc,char* argv[])
{
        if(argc!=2)
        {
                printf("命令名+IP\n");
                return 1;
        }
        int skt = socket(AF_INET,SOCK_STREAM,0);
        if(skt == -1)
        {
                printf("socket error.\n");
                return 1;
        }
        struct sockaddr_in servaddr;
        servaddr.sin_port = htons(9877);
        servaddr.sin_family = AF_INET;
        inet_pton(AF_INET,argv[1],&servaddr.sin_addr);
        int ret=connect(skt,(struct sockaddr*)&servaddr,sizeof(servaddr));
        if(ret == -1)
        {
                printf("connect error.\n");
                return 1;
        }
        char line[1024],recv[1024];
        while(scanf("%s",line)!=EOF)
        {
                write(skt,line,strlen(line));
                int n= read(skt,recv,sizeof(recv));
                recv[n] = 0;
                printf("%s\n",recv);
        }
       
}
作者: converse    时间: 2009-04-24 11:22
>>当第二个以上的连接连入时,客户端输入时,会阻塞在select函数

这是因为你传给select的timeout参数是NULL,man select可知:
If timeout is NULL (no timeout), select() can block indefinitely.

因此只有当client有输入时,select才会返回.
作者: cgp2001    时间: 2009-04-24 11:28
第二个客户我也有输入啊,然后按了回车,这时服务器上第二个客户的已连接套接口就会准备好啊,不知道这样理解对不对?
但实际情况是我在第二个客户上输入了,也按了回车,还是没有反应。
这时再在第一个客户上输入,第二个客户的才会回射回来。
作者: converse    时间: 2009-04-24 11:32
你这个代码可以编译过去?

if(client<0)
                                {
                                        client = connfd;
                                        break;
                                }


client是一个int数组
作者: cgp2001    时间: 2009-04-24 11:36
可以啊。这个应该关系不大吧,实际上都是整数,书上也是写的int.难道跟这个有关?
作者: hellioncu    时间: 2009-04-24 11:37
原帖由 converse 于 2009-4-24 11:32 发表
你这个代码可以编译过去?

if(client


Smilies搞的鬼,字都成斜体了
作者: cgp2001    时间: 2009-04-24 11:38
我开了两个客户,建立了两个连接,应该是正常的吧。

tcp        2      0 192.168.85.128:9877         192.168.85.128:55242        ESTABLISHED
tcp        0      0 192.168.85.128:9877         192.168.85.128:55241        ESTABLISHED
作者: converse    时间: 2009-04-24 12:52
问题发现了:

照着下面这部分将对应的代码改过来就是了,至于为什么,你自己去想想吧


  1. for(i=0;i<=maxi;++i)
  2.             {   
  3.                 if(client[i]<0)
  4.                     continue;
  5.                 if(FD_ISSET(client[i],&set))
  6.                 {   
  7.                     int n;
  8.                     char line[10240];
  9.                     if((n=read(client[i],line,sizeof(line))) == 0)
  10.                     {   
  11.                         close(client[i]);
  12.                         FD_CLR(client[i],&allset);
  13.                         client[i] = -1;
  14.                     }   
  15.                     else
  16.                     {   
  17.                         printf("read from %d: %s\n", client[i], line);
  18.                         write(client[i],line,strlen(line));
  19.                         memset(line, 0, sizeof(line));
  20.                     }   
  21.                     if(--nready<=0)
  22.                         break;
  23.                 }   
  24.             }   
复制代码

作者: converse    时间: 2009-04-24 12:53
另外,select实际上没有阻塞,不信你top看看你的程序实际上CPU占用率是100%,也就是死循环了.
作者: xinglp    时间: 2009-04-24 13:04
原帖由 cgp2001 于 2009-4-24 11:38 发表
我开了两个客户,建立了两个连接,应该是正常的吧。

tcp        2      0 192.168.85.128:9877         192.168.85.128:55242        ESTABLISHED
tcp        0      0 192.168.85.128:9877         192.1 ...


非阻塞的套接字上,服务器端不用accept()也能ESTABLISHED,只不过用 netstat -anp 看不到进程名

accept()前
tcp  0  0 192.168.1.***:80  192.168.1.***:20393  ESTABLISHED -

accept()后
tcp  0  0 192.168.1.***:80  192.168.1.***:20394  ESTABLISHED 4007/Httpd

[ 本帖最后由 xinglp 于 2009-4-24 13:05 编辑 ]
作者: cgp2001    时间: 2009-04-24 13:23
3ks,我明白了。
作者: cgp2001    时间: 2009-04-24 13:39
原帖由 xinglp 于 2009-4-24 13:04 发表


非阻塞的套接字上,服务器端不用accept()也能ESTABLISHED,只不过用 netstat -anp 看不到进程名

accept()前
tcp  0  0 192.168.1.***:80  192.168.1.***:20393  ESTABLISHED -

accept()后
tcp  0  0  ...



这个太高深了,还没法理解。不过还是谢谢。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2