免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6286 | 回复: 7
打印 上一主题 下一主题

[C] select的返回值老是为0,我有数据输入的 [复制链接]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-08-05 19:10 |只看该作者 |倒序浏览
#include<stdio.h>
#include <stdlib.h>
#include<strings.h>
#include <string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>

#define PORT 4502
#define BACKLOG 1
#define MAXDATASIZE 4000
#define ONLINE 8000 /*定义一个最大5000人在线的情况*/

#define  PTHREAD_THREADS_MAX   50 /*允许一个进程创建这个数量的线程*/

struct ARG
{
    int connfd[ONLINE][6]; //用户信息列表 数字型
    char *connfds[ONLINE][20]; //用户信息列表 字符串型
    int currently,pthread_id[PTHREAD_THREADS_MAX];
    struct sockaddr_in client;
    int pth;//下一个线程
};

////////////////////////////////////////
void *func(void *arg );
int simulate_accept(void *arg,int pt);
int acceptfz(void *arg,int client_fd,int e);

///////////////////////////////////

int main()
{
     pthread_t tid;
    pthread_attr_t attr;

     int listenfd,i, connectfd;
     struct sockaddr_in server;
     struct sockaddr_in client;
     socklen_t addrlen;
     char buf[MAXDATASIZE];
     struct ARG *arg, in;
     arg = &in;
   

    printf("初始化数据\n";
    for (i=0;i<ONLINE;i++)
    {
         //初始化在线人数
        arg->connfd[0]=0;//连接句柄
        arg->connfd[1]=0;//联盟ID
        arg->connfd[2]=0;//门派ID
        arg->connfd[3]=0;//是否允许登陆0为不允许
        arg->connfd[4]=0;//使用那个线程
        arg->connfd[5]=0;//是否已经加入select的句柄集
   
        arg->connfds[0]=(char*)"";//昵称
        arg->connfds[1]=(char*)"";//玩家用户名
    }
    arg->pth=100;

    printf("启动线程\n";
    pthread_attr_init(&attr);
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);//把线程脱离出去
    pthread_attr_setstacksize(&attr,512);//线程堆贱大小

     for(i=0;i<THREAD_THREADS_MAX;i++)
     {
            //创建50个应用线程
         if(pthread_create(&tid,&attr, func, (void *)arg))
         {
              perror("error pthread_create2";
         }
        printf("启动处理线程%d\n",tid);
        arg->pthread_id=tid;//取得线程ID
     }

    printf("建立socket\n";
     if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
     {
        perror("socket() error.";
        //exit(1);
     }
     
     int opt = 1;
     setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
     
     bzero(&server, sizeof(server));
     server.sin_family = AF_INET;
     server.sin_port = htons(PORT);
     server.sin_addr.s_addr = htonl(INADDR_ANY);
     if(bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1)
     {
          perror("bind() error.";
          //exit(1);
     }
     if(listen(listenfd, BACKLOG) == -1)
     {  
          perror("listen() error.";
          //exit(1);
     }
     printf("主程序进入守护状态\n";
     addrlen = sizeof(client);
     while(1)
     {
         if((arg->currently= accept(listenfd, (struct sockaddr *)&client, &addrlen )) == -1)
         {
              perror("accept() error.";
              //exit(1);
         }
        acceptfz(arg,arg->currently,1);//像socket注册句柄
     }
    return 0;
}

void *func(void *arg)
{
    //便利属于这个线程的100个用户
    //pthread_detach(pthread_self());//上面已经把这个线程分离出来啦
    struct ARG *args;
    args =  (struct ARG *)arg;

    int retval,i,j,pt=pthread_self();//取得线程ID
    int in=0;
    char *tmp[20];
    char*bufs = (char *) malloc ( sizeof(int) *MAXDATASIZE);

    fd_set rfds;
    struct timeval tv;
    int oks=0,maxfd=-1;
   
    maxfd = 0;

    while(1)
    {
            i=simulate_accept(args,pt);//返回用户下标
            printf("句柄分析 %i-------用户序列号:%i\n",args->connfd[0],i);
            //提取出属于自己线程的句柄,并且句柄不能为0
            
            //是否加入集合中
            if(args->connfd[5]==0)
            {
                //把集合清空
                FD_ZERO(&rfds);
                // 把当前连接句柄new_fd加入到集合中
                FD_SET(args->connfd[0], &rfds);
                args->connfd[5]=1;
                printf("已将句柄 %i 加入到集合中----%i\n",args->connfd[0],i);
            }
            
            if (args->connfd[0] > maxfd)
            {
                maxfd = args->connfd[0];
            }
            // 设置最大等待时间
            tv.tv_sec = 0;
            tv.tv_usec =100;
            //printf("最大句柄----%i\n",maxfd);
        
            // 开始等待
            retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
        
            if (retval == -1)
            {
                perror("select error.";
               continue;
           } else if (retval == 0) {
               //printf("没有任何消息到来,继续等待……%i\n",i);
                continue;
            } else {
                printf("有一个操作信号\n");
                if (FD_ISSET(args->connfd[0], &rfds))
                {
                        memset(bufs, 0, MAXDATASIZE);
                        memset(tmp, 0, 20);
                        
                         if (read(args->connfd[0], bufs, MAXDATASIZE)< 0)
                        {
                                perror("read error");
                                acceptfz(args,args->connfd[0],0);
                                close(args->connfd[0]);
                                //exit(0);
                                 continue;
                        }
                        
                        printf("读取客户端信息: %s\n",bufs);
                }
            }
    }
}



//将accept加入到用户列表中或注销
int acceptfz(void *arg,int client_fd,int e)
{
    struct ARG *info;
    info =  (struct ARG *)arg;
    int j;
    if(e==1)
    {
        for(j=0;j<ONLINE;j++)
        {
                //找一个空的句柄存储仓
                if(info->connfd[j][0]==0)
                {
                    //将句柄交给存储仓
                    info->connfd[j][0]=client_fd;//句柄注册
               
                    //为句柄分配线程号
                    if(info->pth==100 || info->pth==PTHREAD_THREADS_MAX)
                    {
                        info->pth=1;
                        info->connfd[j][4]=info->pthread_id[0];//初始化第一个
                    }else{
                        info->connfd[j][4]=info->pthread_id[info->pth];
                        printf("新线程号:%i--------pth:%i\n",info->pthread_id[info->pth],info->pth);
                        info->pth++;
                    }
               
                    printf("将连接句柄交给%s:%i,线程号:%i\n","connfd",info->connfd[j][0],info->connfd[j][4]);
                    return j;
                }
        }
    }else{
        for(j=0;j<ONLINE;j++)
        {
            if(info->connfd[j][0]==client_fd)
            {
                printf("用户:%i连接被销毁\n", info->connfd[j][0]);
               
                info->connfd[j][0]=0;
                info->connfd[j][1]=0;
                info->connfd[j][2]=0;
                info->connfd[j][3]=0;
                info->connfd[j][4]=0;
                info->connfd[j][4]=0;
            
                info->connfds[j][0]="";
                info->connfds[j][1]="";
               
                pthread_exit((char*)pthread_self());//销毁线程释放内存
                break;
            }
        }
    }
    return 0;
}


int simulate_accept(void *arg,int pt)
{
    struct ARG *args;
    args =  (struct ARG *)arg;
    int i,j,oks=0;
    //int j = (int ) malloc (sizeof(int)* 5);
    for(i=0;i>-1;i++)
    {
        if(i==ONLINE){i=0;}
            
        for (j=0;j<ONLINE;j++)
        {
            if(args->connfd[j][4]==pt && args->connfd[j][0]!=0 && args->connfd[j][5]==0)
            {
                printf("已经检查到一个新句柄 %i----用户序列号:%i----是否在集合中%i\n",args->connfd[j][0],j,args->connfd[j][5]);
                return j;
            }
        }
        
        if(oks==0)
        {//句柄列表中是否有有效的连接
            //printf("线程处于等待状态%d\n",pt);
            sleep(1);
             continue;
        }
    }
}

代码我是提取出来的,帮我看看逻辑是否有问题,我是新学C的,忘高手帮忙看下为什么select检查不到我前台发送过来的数据(就是read给没被执行到郁闷,连接正常)。
这个是我自己写的,我的思路是想让一个线程守候端口,如果有客户端连接则忘一个数组里把这个句柄加入到数组中,
然后其他50个线程就处理这个数组中的数据,acceptfz函数在守候线程里就开始分配句柄属于那个线程的

[ 本帖最后由 jd808 于 2009-8-6 16:18 编辑 ]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
2 [报告]
发表于 2009-08-06 11:18 |只看该作者
没人给个意见??

论坛徽章:
0
3 [报告]
发表于 2009-08-06 12:20 |只看该作者
代码太长了

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
4 [报告]
发表于 2009-08-06 12:59 |只看该作者
这是一个基本的呀,在精简了你们就找不到问题所在,而且还不知道代码到底是干什么的

论坛徽章:
0
5 [报告]
发表于 2009-08-06 14:19 |只看该作者
程序有够乱的,这么简单的功能写出这么复杂的代码来。你的线程中是不是可以select多个socket?那你每得一个新的之后好像就FD_ZERO了,只有一个。另外看如下判断:
            //是否加入集合中

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(args->connfd[5]==0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//把集合清空

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FD_ZERO(&rfds);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 把当前连接句柄new_fd加入到集合中

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FD_SET(args->connfd[0], &rfds);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;args->connfd[5]=1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("已将句柄 %i 加入到集合中----%i\n",args->connfd[0],i);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}


如果这段代码不是每次都执行那问题就来了,select的几个文件句柄集合都是In-Out参数,一旦超时一次集合中全部为空。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
6 [报告]
发表于 2009-08-06 16:03 |只看该作者
大哥 代码不简单啊,里面很多功能我只是把代码抽取出来才显得比较乱的
上面那段代码是否执行要看  
i=simulate_accept(args,pt);
当他接收到一个新的句柄之后就返回(属于本线程的),否者就一直挺在这里呢 与真正的accept效果差不多的方式。
不然的话 func 函数可能就一直处于死循环很消耗cpu呢
当然前面的程序把接到的句柄分配给这个线程的时候,而这个线程见到有新的句柄加入就会执行下面,那个args->connfd[5]是用来判断是否已经加入到集合中,这个其实在simulate_accept函数里我已经判断过的,
分配句柄交给那个线程处理是油 acceptfz(arg,arg->currently,1);
函数处理,这些还数我都贴出,带回我把他弄成彩色的加在下面方便你们观看
if(args->connfd[5]==0)
{
    //把集合清空

    FD_ZERO(&rfds);
    // 把当前连接句柄new_fd加入到集合中

    FD_SET(args->connfd[0], &rfds);
    args->connfd[5]=1;
    printf("已将句柄 %i 加入到集合中----%i\n",args->connfd[0],i);
}


[ 本帖最后由 jd808 于 2009-8-6 16:14 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2009-08-06 16:12 |只看该作者
最好是用一个变量来存rfds的值。
然后才传给select,

因为select执行后会改娈rfds的值。你最好再去了解一下select是如何工作的。

我没也没仔细看你的代码,因为太长了。

[ 本帖最后由 xieweihua 于 2009-8-6 16:13 编辑 ]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
8 [报告]
发表于 2009-08-06 16:15 |只看该作者
发不了彩色的 没办法说太长了,在说了分太多次发你们也不定看的舒服

[ 本帖最后由 jd808 于 2009-8-6 16:17 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP