select服务器与客户端
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11
12 #define ERR_MSG(msg) do{\
13 fprintf(stderr,"line:%d ",__LINE__);\
14 perror(msg);\
15 }while(0);
16
17 #define IP "192.168.2.145" //本机IP
18 #define PORT 6767 //端口号1024~49151
19
20 int main(int argc, const char *argv[])
21 {
22 //创建流式套接字
23 int sfd = socket(AF_INET,SOCK_STREAM,0);
24 if(sfd < 0)
25 {
26 ERR_MSG("socket");
27 return -1;
28 }
29
30 //允许端口快速重用
31 int reuse = 1;
32 if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0)
33 {
34 ERR_MSG("setsockopt");
35 return -1;
36 }
37 printf("允许端口快速重用成功\n");
38
39
40
41 //填充地址信息结构体
42 struct sockaddr_in sin;
43 sin.sin_family = AF_INET; //必须填AF_INET
44 sin.sin_port = htons(PORT); //端口号
45 sin.sin_addr.s_addr = inet_addr(IP); //本机IP
46
47 //将IP和端口绑定到套接字上
48 if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
49 {
50 ERR_MSG("bind");
51 return -1;
52 }
53 printf("bind success __%d__\n",__LINE__);
54
55 //将套接字设置为被动监听状态,监听是否有客户端连接成功;
56 if(listen(sfd,128) < 0)
57 {
58 ERR_MSG("listen");
59 return -1;
60 }
61 printf("listen sucess __%d__\n",__LINE__);
62
63
64 struct sockaddr_in cin;//存储连接成功的客户端地址信息
65 struct sockaddr_in home_cin[1024-4];//存储连接成功的客户端地址信息
66 socklen_t addrlen = sizeof(cin);
67
68 //阻塞函数,从已完成连接的队列头中获取一个客户端信息,生成一个新的文件描述符
69 //该文件描述符才是与客户端通信的文件描述符
70
71
72
73 //设置一个读集合
74 fd_set readfds,tmpfds;
75 FD_ZERO(&readfds);
76 FD_ZERO(&tmpfds);
77
78 //将需要的文件描述符添加到集合中
79 FD_SET(0,&readfds);
80 FD_SET(sfd,&readfds);
81
82 int maxfd = sfd;
83
84 int s_res = 0;
85 char buf[128] = "";
86 ssize_t res = 0;
87 int newfd = -1;
88 while(1)
89 {
90 tmpfds = readfds;
91 s_res = select(maxfd+1,&tmpfds,NULL,NULL,NULL);
92 if(s_res < 0)
93 {
94 ERR_MSG("select");
95 return -1;
96 }
97
98 else if(0 == s_res)
99 {
100 printf("time out...\n");
101 return -1;
102 }
103
104 //能运行到当前位置,则代表有文件描述符准备就绪
105 //走触发事件的文件描述符对应的处理函数
106
107 //当集合中有文件描述符准备就绪了,集合中只保留产生事件的文件描述符
108 //当0准备就绪,集合中会只保留0
109 //当sfd准备就绪,集合中会只保留sfd
110 //当0和sfd都准备就绪,,集合中会保留0和sfd
111 //所以只需要判断集合中剩下哪个文件描述符,走对于函数即可
112
113 for( int i = 0;i<=maxfd;i++)
114 {
115 if(!FD_ISSET(i,&tmpfds)) //如果不在集合中,则直接往后继续变量
116 {
117 continue;
118 }
119
120
121 //能运行到当前位置,则说明i所代表的文件描述符在tmpfds中
122 //要判断i所代表的文件描述符需要走什么对应的函数
123 if(0 == i)
124 {
125 printf("触发键盘输入事件>>>");
126 scanf("%s",buf);
127 while(getchar() != 10);
128 printf(":%s\n",buf);
129
130 }
131
132 else if(sfd == i)
133 {
134 printf("触发客户端连接事件>>>");
135 fflush(stdout);
136 newfd = accept(sfd,(struct sockaddr*)&cin,&addrlen);
137 if(newfd < 0)
138 {
139 ERR_MSG("accept");
140 return -1;
141 }
142 home_cin[newfd-4]=cin;
143 printf("[%s:%d] newfd = %d 连接成功__%d__\n",inet_ntoa(cin.sin_addr),ntohs(home_cin[i-4].sin_port),newfd,__LINE__);
144
145 //将newfd添加到读集合中
146 FD_SET(newfd,&readfds);
147 //更新maxfd
148 maxfd = maxfd>newfd?maxfd:newfd;
149 }
150
151 else
152 {
153 bzero(buf,sizeof(buf));
154 //接收
155 res = recv(i,buf,sizeof(buf),0);
156 if(res < 0)
157 {
158 ERR_MSG("recv");
159 return -1;
160 }
161 else if(0 == res)
162 {
163 printf("[%s:%d] newfd=%d 客户端下线 __%d__\n",inet_ntoa(cin.sin_addr),ntohs(home_cin[i-4].sin_port),newfd,__LINE__);
164 //关闭文件描述符
165 close(i);
166 //从集合中提出该文件描述符
167 FD_CLR(i,&readfds);
168
169 //更新maxfd,
170 //从目前最大的文件描述符往小的判断,直到判断在集合中
171 //那么该文件描述符就是最大的
172 int j = 0;
173 for(j=maxfd;j>=0;j--)
174 {
175 if(FD_ISSET(j,&readfds))
176 {
177 maxfd=j ;
178 break;
179 }
180 }
181 if(j < 0)
182 maxfd = -1;
183
184 continue;
185
186 }
187 strcat(buf,"*.*");
188 send(i,buf,sizeof(buf),MSG_DONTWAIT);
189 printf("[%s:%d] newfd = %d:%s\n",inet_ntoa(cin.sin_addr),ntohs(home_cin[i-4].sin_port),i,buf);
190 }
191 }
192
193
194 }
195
196
197
198
199 /*
200
201
202
203 //发送
204 strcat(buf,"*_*");
205 if(send(newfd,buf,sizeof(buf),0) < 0)
206 {
207 ERR_MSG("send");
208 return -1;
209 }
210 printf("发送成功\n");
211 */
212
213 return 0;
214 }
~
~
~
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11
12
13 #define ERR_MSG(msg) do{\
14 fprintf(stderr,"line:%d ",__LINE__);\
15 perror(msg);\
16 }while(0);
17
18 #define IP "192.168.2.145" //服务器IP
19 #define PORT 6767 //端口号1024~49151
20
21 int main(int argc, const char *argv[])
22 {
23 //创建流式套接字
24 int cfd = socket(AF_INET,SOCK_STREAM,0);
25 if(cfd < 0)
26 {
27 ERR_MSG("socket");
28 return -1;
29 }
30
31
32 //绑定客户端的地址信息结构体,非必须绑定的
33 //如果不绑定,则由操作系统自动选择一个端口号,以及本机可用IP绑定到套接字上
34 //将IP和端口绑定到套接字上
35 /*
36 if(bind(cfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
37 {
38 ERR_MSG("bind");
39 return -1;
40 }
41 printf("bind success __%d__\n",__LINE__);
42 */
43 //填充服务器地址信息结构体
44 struct sockaddr_in sin;
45 sin.sin_family = AF_INET; //必须填AF_INET
46 sin.sin_port = htons(PORT); //端口号
47 sin.sin_addr.s_addr = inet_addr(IP); //本机IP
48
49 //连接服务器
50 if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
51 {
52 ERR_MSG("connect");
53 return -1;
54 }
55 printf("connect sucess __%d__\n",__LINE__);
56
57 char buf[128] = "";
58 ssize_t res = 0;
59 while(1)
60 {
61 //发送
62 bzero(buf,sizeof(buf));
63 fscanf(stdin,"%s",buf);
64 buf[strlen(buf)] = 0;
65 if(send(cfd,buf,sizeof(buf),0) < 0)
66 {
67 ERR_MSG("send");
68 return -1;
69 }
70 printf("发送成功\n");
71
72 //终端输入quit后退出程序
73 if(strcasecmp(buf,"quit") == 0)
74 break;
75
76 //接收
77 bzero(buf,sizeof(buf));
78 res = recv(cfd,buf,sizeof(buf),0);
79 if(res < 0)
80 {
81 ERR_MSG("recv");
82 return -1;
83 }
84 else if(0 == res)
85 {
86 printf("cfd = %d服务器下线 __%d__\n",cfd,__LINE__);
87 break;
88 }
89 printf("cfd = %d:%s\n",cfd,buf);
90
91
92 }
93
94
95
96 close(cfd);
97
98
99 return 0;
100 }