免费注册 查看新帖 |

Chinaunix

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

请教select的用法 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-04-29 15:38 |只看该作者 |倒序浏览
我在用socket编程时服务器端使用子进程去处理连接后的通信.
代码如下:

  1. int Init_Net_OP()
  2. {
  3.   int sockfd,connfd;
  4.   struct sockaddr_in serv_addr,client_addr;
  5.   int sin_size;

  6.   if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
  7.   {
  8.     fprintf(stderr,"socket error!\n");
  9.     return -1;
  10.   }

  11.   serv_addr.sin_family=AF_INET;
  12.   serv_addr.sin_port=htons(SERV_PORT);
  13.   serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);

  14.   if(bind(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr))==-1)
  15.   {
  16.     fprintf(stderr,"bind error!\n");
  17.     return -1;
  18.   }

  19.   if(listen(sockfd,BACKLOG)==-1)
  20.   {
  21.     fprintf(stderr,"listen error!\n");
  22.     return -1;
  23.   }

  24.   while(1)
  25.   {
  26.     sin_size=sizeof(struct sockaddr_in);
  27.     if((connfd=accept(sockfd,(struct sockaddr *)&client_addr,&sin_size))==-1)
  28.     {
  29.       fprintf(stderr,"accept error!\n");
  30.       continue;
  31.     }
  32.     printf("server got connection from %s\n",inet_ntoa(client_addr.sin_addr));
  33.     /*
  34.     strcpy(key,"rc6keyabcdefghijllmnopqresuvwxyz");
  35.     server_init(connfd,key);
  36.     */
  37.    
  38.     if(!fork())
  39.     {
  40.       close(sockfd);
  41.       strcpy(key,"rc6keyabcdefghijllmnopqresuvwxyz");
  42.       if(server_init(connfd,key)==-1)//一些初始化操作
  43.       {
  44.         close(connfd);
  45.         close(connfd);
  46.         continue;
  47.       }
  48.       close(connfd);
  49.       exit(0);
  50.     }
  51.     close(connfd);
  52.     while(waitpid(-1,NULL,WNOHANG)>;0);
  53.   }
  54. }

复制代码

现在老师要求我在以后的通信中无论服务器或是客户端都可以\随时发送或是接收信息.但是我不懂该怎么做,要实现双方通信就必需一方是write而另一方就是read.这样才能收到吧.   要实现随时可收可发该怎么办呢?

可不可以在服务器的子进程中使用select同时监听这一描述符的听和写呢?
有没有谁可以帮我解决这个问题?感激不尽!!!  

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
2 [报告]
发表于 2003-04-29 17:23 |只看该作者

请教select的用法

前面的帖子或者精华区有过select谈论,麻烦你去找找,可以解决你的问题。

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
3 [报告]
发表于 2003-04-29 18:29 |只看该作者

请教select的用法

例如:

  1. # include <sys/types.h>;
  2. # include <sys/socket.h>;
  3. # include <netinet/in.h>;
  4. # include <netdb.h>;
  5. # include <stdio.h>;
  6. # include <unistd.h>;
  7. # include <time.h>;

  8. //define some general viriables
  9. //log file 50!
  10. //record file 100! message

  11. void gettime();
  12. int num=0;//num为客户端socket数组专用…
  13. int number;//number是特定客户端数组socket号…
  14. char history[20]; //询问历史信息记录文件名…
  15. int userfd[20]; //很有用的…
  16. char *id[20]; //标明该用户地址…
  17. char timenow[25]; //标明此时服务器时间…
  18. char today[8]; //例如:20010412…
  19. char todayinfo[13]; //信息记录文件名…
  20. char todaylog[12]; //操作日志文件名…
  21. char message[46]; //发送信息数组…

  22. int inspect[20];

  23. char infofromclient[50];// his,msg info comes here!
  24. int fd1,fd2,fd; //record文件…log文件…history文件…!

  25. main()
  26. {
  27. int sockfd,maxfd=1;//sockfd is the socket for listening,maxfd is the max number of socket
  28. fd_set readfds;//readfds is the collection of the client sockets
  29. char showin[29]; //showin!!!!!!!
  30. int k;
  31. int i;
  32. int port;
  33. struct sockaddr_in server;
  34. char request[3];
  35. int namelen;

  36. /******************* realcode here ***********************/
  37. for (k=1;k<=19;k++)
  38. inspect[k]=1; //to make the out off!!

  39. sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  40. if(sockfd<0)
  41. {
  42. perror("socket");
  43. exit(1);
  44. }
  45. server.sin_family=AF_INET;
  46. server.sin_addr.s_addr=INADDR_ANY;
  47. server.sin_port=htons(3333);
  48. if(bind(sockfd,&server,sizeof(server))<0)
  49. {
  50. perror("bind");
  51. exit(2);
  52. }
  53. printf("bind ok\n"); //+++++++++++++++temp+++++++++++++++
  54. if(listen(sockfd,5)<0)
  55. {
  56. perror("listen");
  57. exit(3);
  58. }
  59. printf("listen ok\n"); //+++++++++++++++temp+++++++++++++++

  60. FD_ZERO( &readfds); //处理……
  61. FD_SET( sockfd, &readfds);

  62. for ( k=0;k<=num;k++)
  63. FD_SET( userfd[k], &readfds); //加入集中去…

  64. /*** 发现错误后增加如下语句
  65. maxfd=sockfd+1;
  66. /***


  67. //////////////////////////////////////////////////////////////////////
  68. //is the main loop while

  69. userfd[0]=0;// 0 is empty!
  70. while(1)

  71. {
  72. if (userfd[num]>;maxfd)
  73. maxfd=userfd[num]; //needn't

  74. select( maxfd, &readfds, NULL, NULL, NULL); //判断maxfd

  75. //case 1 :if some new client comes
  76. if ( FD_ISSET( sockfd, &readfds))
  77. {
  78. printf("get connect\n");//debug
  79. num++;
  80. namelen=sizeof(server);
  81. if((userfd[num]=accept(sockfd,&server,&namelen))<0)
  82. //建立新连接, 并将该连接描述符加入到 sockset 中去了,此为有新连接…
  83. {
  84. perror("accept");
  85. exit(4);
  86. } //如果退出,那…
  87. printf("server: got connection from %s\n",inet_ntoa(server.sin_addr));

  88. strcpy(id[num],"203.93.49.33");//inet_ntoa(server.sin_addr)); **@@##

  89. printf("new connection from %s/n",id[num]); //IP地址
  90. printf("a new user comes!!");

  91. gettime();
  92. strncpy(todaylog,today,8);
  93. strcat(todaylog,".log");
  94. if ((fd1=open(todaylog))==-1)
  95. {
  96. creat(todaylog,2);
  97. fd1=open(todaylog,2);
  98. }

  99. write(fd1,id[num],20); //保存
  100. write(fd1,":",2); //操作
  101. write(fd1,"IN",6); //日志
  102. write(fd1,":",2); //文件
  103. write(fd1,timenow,30); //时间

  104. strncpy(showin,id[num],20);
  105. strcat(showin,"has come!");
  106. for(k=1;k<num;k++)
  107. if (inspect[k])
  108. write(userfd[k],showin,29);

  109. FD_SET(userfd[num],&readfds); //加到集中…because of linked recently;

  110. }
  111. //end case 1:end some new client comes

  112. //case 2:if some connected clients send some message
  113. for ( k=1;k<=num;k++)
  114. {
  115. if (FD_ISSET(userfd[k], &readfds))
  116. {
  117. number=k;
  118. read(userfd[k],infofromclient,50);
  119. printf("%s\n",infofromclient);
  120. strncpy(request,infofromclient,3);
  121. gettime();
  122. strncpy(todaylog,today,8);
  123. strcat(todaylog,".log");
  124. if ((fd1=open(todaylog))==-1)
  125. {
  126. creat(todaylog,2);
  127. fd1=open(todaylog,2);
  128. }
  129. write(fd1,id[number],20); //保存
  130. write(fd1,":",2); //操作
  131. write(fd1,request,6); //日志
  132. write(fd1,":",2); //文件
  133. write(fd1,timenow,30); //时间

  134. //MMM SSSS GGG @@@

  135. if (strcmp(request,"MSG")==0)
  136. {
  137. gettime();
  138. strncpy(todayinfo,today,8);
  139. strcat(todayinfo,".info");
  140. if ((fd2=open(todayinfo,2))==-1)
  141. {
  142. creat(todayinfo,2);
  143. fd2=open(todayinfo,2);
  144. }
  145. for(i=0;i<=45;i++)
  146. message=infofromclient[i+4];

  147. msg();
  148. }

  149. //HHH IIII SSS @@@

  150. /* if (strcmp(request,"HIS")==0)
  151. {
  152. for(i=0;i<=14;i++)
  153. history=infofromclient[i+4];
  154. strcat(history,".info");

  155. if ((fd=open(history,2))==-1)
  156. {
  157. printf("the file dosn't exist!");
  158. exit(6);
  159. }
  160. do
  161. {
  162. his();
  163. sleep(1); //pause in order to let client read!!
  164. }
  165. while(!eof(fd1));
  166. }*/
  167. if (strcmp(request,"OUT")==0)
  168. out();
  169. }
  170. }
  171. //end case 2:end some connected clients send some message

  172. }
  173. //end of main loop while


  174. } //OK! end main

  175. ///////////////////////////////////////////////////////////////////////

  176. msg()
  177. {
  178. int k;
  179. char record[100];
  180. write(fd2,id[number],20); //保存
  181. write(fd2,":",2); //信息
  182. write(fd2,message,46); //记录
  183. write(fd2,":",2); //文件
  184. write(fd2,timenow,30); //时间
  185. lseek(fd2,-100L,2);
  186. read(fd2,record,100);
  187. for ( k=0;k<=num;k++)
  188. if (inspect[k])
  189. write(userfd[k],record,100);
  190. lseek(fd2,100L,1);
  191. }



  192. his()
  193. {
  194. char onerecord[100];
  195. read(fd,onerecord,100);
  196. write(userfd[number],onerecord,100);
  197. lseek(fd1,100L,1);
  198. }


  199. out()
  200. {
  201. int k;
  202. char showout[31];
  203. strncpy(showout,id[number],20);
  204. strcat(showout,"is out yet!",11);
  205. shutdown(userfd[number],2);
  206. for(k=1;k<=num;k++)
  207. if (inspect[k])
  208. write(userfd[k],showout,31);
  209. inspect[k]=0;
  210. }


  211. void gettime()
  212. {
  213. time_t timer;
  214. char mon[2];
  215. char year[4];
  216. char mday[2];
  217. char year1[4];
  218. char mday1[2];
  219. char mon1[2];
  220. struct tm *t;
  221. timer=time(NULL);
  222. t=localtime(&timer);
  223. strcpy(timenow,asctime(t));
  224. (t->;tm_mon)++;
  225. sprintf(mon1,"%d",t->;tm_mon);
  226. if (t->;tm_mon/10==0)
  227. {
  228. strcpy(mon,"0");
  229. strcat(mon,mon1);
  230. }
  231. else strcpy(mon,mon1);
  232. t->;tm_year+=1900;
  233. sprintf(year1,"%d",t->;tm_year);
  234. strcpy(year,year1);
  235. strcpy(today,year);
  236. sprintf(mday1,"%d",t->;tm_mday);
  237. if (t->;tm_mday/10==0)
  238. {
  239. strcpy(mday,"0");
  240. strcat(mday,mday1);
  241. }
  242. else strcpy(mday,mday1);
  243. strncat(today,mon,2);
  244. strncat(today,mday,2);
  245. }
复制代码

论坛徽章:
0
4 [报告]
发表于 2003-04-29 19:09 |只看该作者

请教select的用法

谢谢
不过我的问题和平时使用select不太一样,我在服务器端已经使用了  子进程.这样就不存在利用select监听是否有新连接或是哪个描述符上可读,可写.

我现在是想在子进程中利用select来判断此时在这个描述符上是否有消息进入,如果有则希望服务器能调用read函数接收,并且做出相应的处理后对客户端发出回复,当然我希望此时client端也能够接收,即client也具备server端的能力,可随时接收,发送.

论坛徽章:
0
5 [报告]
发表于 2003-04-30 08:36 |只看该作者

请教select的用法

client和sever可以同时收?
我觉得这样的模型应该不是很好

一般一个socket专门由一个程序负责
不可以多个cient同时用
虽然同时用是技术上可以的

但是编程时会很混乱
我觉得还是改改你的软件设计好

论坛徽章:
0
6 [报告]
发表于 2003-04-30 09:16 |只看该作者

请教select的用法

无双,我不懂哎.

我的程序是这样的: 在server端由一个listenfd来监听是否有client申请连接,如果有就创建一个子进程去完成以后与这个客户的通信.  我现在是想在这个子进程中可以做到与client随时发送,接收消息,所以我想是不是可以在server的子进程中使用select来完成判断是否可读或可写.  但是这只是我的想法,因为我觉得实现起来好像不怎么简单,而且我都不知道能不能达到我的目的.

请问有什么好的建议吗?

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
7 [报告]
发表于 2003-04-30 09:21 |只看该作者

请教select的用法

原帖由 "wangcui" 发表:
谢谢
不过我的问题和平时使用select不太一样,我在服务器端已经使用了  子进程.这样就不存在利用select监听是否有新连接或是哪个描述符上可读,可写.

我现在是想在子进程中利用select来判断此时在这个描述符上是否..........


如果server端使用了select,client端可以直接调用read或recv接受。如果client端要处理来自多个server的响应报文,建议这种情况client也用select处理。

论坛徽章:
0
8 [报告]
发表于 2003-04-30 09:22 |只看该作者

请教select的用法

我在服务器的子进程中这样写的

  1. if(!fork())
  2.     {
  3.       close(sockfd);
  4.       
  5.       strcpy(key,"rc6keyabcdefghijllmnopqresuvwxyz");
  6.       if(server_init(connfd,key)==-1)
  7.       {
  8.         close(connfd);
  9.         close(connfd);
  10.         continue;
  11.       }
  12.       
  13.       struct timeval time;
  14.       fd_set rdset;
  15.       fd_set wrset;
  16.       int n;
  17.       time.tv_sec=60;
  18.       time.tv_usec=0;
  19.       char ch[256];
  20.       while(1)
  21.       {
  22.         FD_ZERO(&rdset);
  23.         FD_ZERO(&wrset);
  24.         FD_SET(connfd,&rdset);
  25.         FD_SET(connfd,&wrset);
  26.         n=select(connfd+1,&rdset,&wrset,NULL,&time);
  27.         if(n==0)
  28.         {
  29.           fprintf(stderr,"select timeout.\n");
  30.           break;
  31.         }
  32.         else
  33.         {
  34.           if(n<0&&errno==EINTR) continue;
  35.           else if(n<0)
  36.           {
  37.             fprintf(stderr,"select return -1!\n");
  38.             exit(1);
  39.           }
  40.         }
  41.         if(FD_ISSET(connfd,&rdset))
  42.         {//其实我是想在这里接收信息后,经过处理紧接着就能发出回复
  43.           //可是这样就不能保证server端现在可发信息,而client也能收到.
  44.            //handle_msg(connfd);
  45.            /*test*/
  46.            memset(ch,0,sizeof(ch));
  47.            read(connfd,ch,sizeof(ch));
  48.            printf("get from client:%s\n",ch);
  49.         }
  50.         if(FD_ISSET(connfd,&wrset))
  51.         {
  52.            /*test*/
  53.            strcpy(ch,"hello,this is server!\n");
  54.            write(connfd,ch,sizeof(ch));
  55.         }
  56.          
  57.         //handle_msg(connfd);
  58.       }
  59.       
  60.       close(connfd);
  61.       exit(0);
  62.     }
复制代码

论坛徽章:
0
9 [报告]
发表于 2003-04-30 09:28 |只看该作者

请教select的用法

哎呀,看来我的表达能力有待加强了.
一个client端只需与一个server端通信.只不过client和server都不知道什么时候会接收到对方的信息.所以既要一直监听是否有消息来,又要顾及自己的消息能否顺利发给对方.

我也想到两边都用select,试试吧!
多谢!

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
10 [报告]
发表于 2003-04-30 09:43 |只看该作者

请教select的用法

原帖由 "wangcui" 发表:
无双,我不懂哎.

我的程序是这样的: 在server端由一个listenfd来监听是否有client申请连接,如果有就创建一个子进程去完成以后与这个客户的通信.  我现在是想在这个子进程中可以做到与client随时发送,接收消息,所以..........


对于你的这种情况,你在server端由一个listenfd来监听是否有client申请连接,如果有就创建一个子进程去完成以后与这个客户的通信.  这个很好,现在看看是怎么回事,一旦select正常返回(假设返回的就是来自client的一个连接请求),那么表示这个时候accept从队列中取出的描述字(也就是你的程序获得的那个描述字)是完成了三路握手的,是可用的。在子进程中,可以直接的针对这个套接口读写数据。如果client端没有作主动关闭,这种读写一定是成功的。没必要在这个时候在select。但是你可能会问,要是client端主动关闭了,我这个时候怎么能在子进程中知道这种情况呢?这个问题的解决其实放在了select中作的,因为client端要做主动的关闭,那么对于socket来说,属于一次不同的请求了,这个和你前面建立的连接没有必然关系。这时候select会有一次返回描述字可读的,对于返回,一般的作socket转台的检查,从来得知是否可读写信息。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP