2014年7月26日星期六

Socket网络编程--聊天程序(4) - 无脑仔的小明

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Socket网络编程--聊天程序(4) - 无脑仔的小明  阅读原文»

  上一小节讲到可以实现多客户端与服务器进行通讯,对于每一个客户端的连接请求,服务器都要分配一个进程进行处理。对于多用户连接时,服务器会受不了的,而且还很消耗资源。据说有个select函数可以用,好像还很NB的样子。

  使用select多路转换处理聊天程序

  下面摘取APUE 14.5小结 I/O多路转接

当从一个描述符读,然后又写到另一个描述符时,可以在下列形式的循环中循环中使用阻塞I/O:

  while((n = read(STDIN_FILENO, buf, BUFFSIZ))>0)

    if(write(STDOUT_FILENO, buf, n)!=n)

      err_sys("write error");

这种形式的阻塞I/O到处可见。但是如果必须从两个描述符读,又将如何呢?如果仍旧使用阻塞I/O,那么就可能长时间阻塞在一个描述符上,而另一个描述符虽有很多数据却不能得到及时处理。所以为了处理这种情况显然需要另一种不同的技术。

方法一:也就是上一小节使用的方法,使用多进程。每一个进程处理一个描述符

方法二:和上面相似的,使用多线程,不同的线程处理不同的描述符

方法三:仍然使用一个进程执行该程序,但使用非阻塞I/O读取数据。然后对所有的描述符进行遍历一遍,判断对应的描述符是否有数据,如果有就读取,如果没有就立即返回。这种办法就是轮询(polling)

方法四:异步I/O。其基本的思想是进程告诉内核,当一个描述符已经准备好可以进行I/O时,用一个信号通知它。

方法五:这是一种比较好的办法。叫做I/O多路转换(I/O multiplexing)。先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已经准备好进行I/O时,该函数才会返回。在返回时,它高数进程哪些描述符已经准备好可以进行I/O。

  poll,pselect和select这三个函数使我们能够执行I/O多路转换。本程序只使用select函数。

  #include <sys/select.h>

  int select (int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds, struct time val *restrict tvptr); //返回值:准备就绪的描述符数,若超时则返回0,否则出错返回-1

  select 函数讲解
  FD_ISSET判断描述符fd是否在给定的描述符集fdset中,通常配合select函数使用,由于select函数成功返回时会将未准备好的描述符位清零。通常我们使用FD_ISSET是为了检查在select函数返回后,某个描述符是否准备好,以便进行接下来的处理操作。

  fd_set数据类型的操作

  #include <sys/select.h>

  int FD_ISSET(int fd, fd_set *fdset);  //判断fd是否在fdset中

  void FD_CLR(int fd, fd_set *fdset);  //进fd从fdset中取出

  void FD_SET(int fd, fd_set *fdset);  //将fd放入fdset

  void FD_ZERO(fd_set *fdset);    //将fdset清空

  timeval结构分析

  struct timeval{

    long tv_sec; //seconds

    long tv_usec; //and microseconds

  };

  client.c的代码没有改

  server.c的代码如下

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <netdb.h>
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <sys/time.h>
9 #include <sys/un.h>
10 #include <sys/ioctl.h>
11 #include <sys/wait.h>
12 #include <sys/select.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15
16 #define SERVER_PORT 12138
17 #define BACKLOG 20
18 #define MAX_CON_NO 10
19 #define MAX_DATA_SIZE 4096
20
21 int MAX(int a,int b)
22 {
23 if(a>b) return a;
24 return b;
25 }
26
27 int main(int argc,char *argv[])
28 {
29 struct sockaddr_in serverSockaddr,clientSockaddr;
30 char sendBuf[MAX_DATA_SIZE],recvBuf[MAX_DATA_SIZE];
31 int sendSize,recvSize;
32 int sockfd,clientfd;
33 fd_set servfd,recvfd;//用于select处理用的
34 int fd_A;//保存客户端的socket描述符
35 int conn_amount;//用于计算客户端的个数
36 int max_servfd,max_recvfd;
37 int on=1;
38 socklen_t sinSize=0;
39 char username[32];
40 int pid;
41 int i;
42 struct timeval timeout;
43
44 if(argc != 2)
45 {
46 printf("usage: ./server \n");
47 exit(1);
48 }
49 strcpy(username,argv[1]);
50 printf("username:%s\n",username);
51
52 /*establish a socket*/
53 if((sockfd = socket(AF_INET,SOCK_STREAM,0))==-1)
54 {
55 perror("fail to establish a socket"ENC28J60 + M430G2553,用uip搭建http服务器,解决"在XP系统下可以访问,在Win7下不能访问"的问题 - Gizmo.G  阅读原文»

近日,用ENC28J60,在M430G2553上搭建一个简单的HTTP服务器,结果发现在XP系统下可以访问,在Win7下不能访问,非常奇葩的问题。

通过抓包,如下图,计算机(IP地址为192.168.1.104)给服务器(IP地址为:192.168.1.150)发动的TCP包中的不添加Checksum信息。

上述问题,导致在uip中直接丢弃此TCP包,如下图。

为了适应默认的Win7系统设置,只能修改uip,让其不做Checksum,把上图的过程注释掉即可。


本文链接:ENC28J60 + M430G2553,用uip搭建http服务器,解决"在XP系统下可以访问,在Win7下不能访问"的问题,转载请注明。

阅读更多内容

没有评论:

发表评论