select实现tcp并发服务器(还没有实现完成)
20 #include <sys/un.h>
21 #define PORT 8888
22 #define IP "192.168.126.52"
23 int main(int argc, const char *argv[])
24 {
25 //1:获取网络通信端点
26 int sfd=socket(AF_INET,SOCK_STREAM,0);
27 if(sfd==-1)
28 {
29 perror("socket error");
30 return -1;
31 }
32 printf("socket success,sfd=%d\n",sfd);
33
34 //2:绑定ip 端口号
35 struct sockaddr_in sin;
36 sin.sin_family=AF_INET;
37 sin.sin_port=htons(PORT);
38 sin.sin_addr.s_addr=inet_addr(IP);
39 if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
40 {
41 perror("bind error");
42 return -1;
43 }
44 printf("bind success\n");
45
46 //3:将套接字设置成被动监听状态
47 if(listen(sfd,128)==-1)
48 {
49 perror("listen error");
50 return -1;
51 }
52 printf("listen success\n");
53
54 //4:阻塞等待客户端连接
55 //定义接收客户端信息容器
56 struct sockaddr_in cin;
57 socklen_t addrlen=sizeof(cin);
58 int newfd=-1;//新建用于通信的套接字文件
59 char rbuf[128]="";//键盘上输入数据
60
61 //11:创建fd_set类型的变量,作为文件描述符容器
62 fd_set readfds,tempfds;
63 //12:清空容器
64 FD_ZERO(&readfds);
65 //13:将SFD和0号文件描述符放入
66 FD_SET(sfd,&readfds);
67 FD_SET(0,&readfds);
68
69 //随着客户端newfd的产生,sfd不在是集合中的文件描述符的最大值
70 int maxfd=sfd;//存放容器中最大文件描述符的最大值
71
72 while(1)//对多个客户端处理,加上循环
73 {
74 tempfds=readfds;//将容器复制一份,因为select函数会删除容器中未触发事件的文件描述符
75 //阻塞等待集合中事件产生
76 int res=select(maxfd+1,&tempfds,0,0,0);
77 if(res==0)
78 {
79 printf("timeout\n");
80 return -1;
81 }
82 else if(res==-1)
83 {
84 perror("select error");
85 return -1;
86 }
87
88 //如果程序执行到此,说明select集合中有事件发生
89 //接下来判断哪个文件描述符发生了事件,发生了事件的文件描述符会留下,其他删除
90 if(FD_ISSET(sfd,&tempfds)) //如果sfd在集合中,说明sfd执行了事件解除了阻塞
91 {
92 newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
93 if(newfd==-1)
94 {
95 perror("accept error");
96 return -1;
97 }
98 printf("newfd=%d,新用户上线,ip地址为%s,端口号为%d\n",newfd,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
99
100
101 //将客户端文件描述符放入集合中
102 FD_SET(newfd,&readfds);
103 //当有新的文件描述符加入到集合中,更新文件描述符的最大值
104 if(newfd>maxfd)
105 {
106 maxfd=newfd;
107 }
108 }
109
110
111 if(FD_ISSET(0,&tempfds))//如果0号描述符在集合中,说明0号描述符执行了事件
112 {
113 //键盘上输入事件
114 fgets(rbuf,sizeof(rbuf),stdin);
115 rbuf[strlen(rbuf)-1]=0;
116 printf("触发了键盘输入事件:%s\n",rbuf);
117 }
118
119 if(FD_ISSET(newfd,&tempfds))//如果newfd在集合中说明客户端执行了事件,执行客户端的代码
120 {
121
122 /* FD_SET(0,&readfds);//事件出发后会删除未触发事件的文件描述符,所以最后添加,但是比较麻烦不用
123 FD_SET(sfd,&readfds); //解决方法是复制一份容器*/
124
125 //5:与客户端进行通信
126 char rbuf[128]="";
127 //while(1) 不需要循环了,循环会导致键盘任务无法触发
128 //{
129 bzero(rbuf,sizeof(rbuf));
130 int res=recv(newfd,rbuf,sizeof(rbuf),0);
131 if(res==0)
132 {
133 printf("对方已下线\n");
134 // break;
135 close(newfd);//关闭套接字
136 continue;//退出进行下一轮while循环会导致键盘任务无法触发
137
138 //将当前关闭的文件描述从readfd集合中移除
139 FD_CLR(newfd,&readfds);
140 //更新maxfd
141
142 }
143 printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),rbuf);
144 strcat(rbuf,"<<<>>>");
145 send(newfd,rbuf,sizeof(rbuf),0);
146 printf("sned success\n");
147 // }
148
149 }
150 }
151 close(sfd);
152
153 return 0;
154 }
~
~