一、select的TCP服务器:
- #include <myhead.h>
-
- #define ERR_MSG(msg) do{\
- fprintf(stderr,"__%d__\n",__LINE__);\
- perror(msg);\
- }while(0)
-
- #define IP "192.168.114.110"
- #define PORT 8888
-
- int main(int argc, const char *argv[])
- {
- //创建流式套接字socket
- int sfd;
- if((sfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
- {
- ERR_MSG("socket");
- return -1;
- }
- printf("socket success sfd = %d\n",sfd);
-
- //允许端口快速被复用
- int reuse =1;
- if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0)
- {
- ERR_MSG("setsockopt");
- return -1;
- }
- printf("允许端口被快速复用成功\n");
-
- //填充地址信息结构体给bind函数使用
- struct sockaddr_in sin;
- sin.sin_family = AF_INET;
- sin.sin_port = htons(PORT); //服务器端口
- sin.sin_addr.s_addr = inet_addr(IP); //服务器IP
-
- //绑定服务器的地址信息
- if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
- {
- ERR_MSG("bind");
- return -1;
- }
- printf("[%s:%d]服务器绑定成功\n",IP,PORT);
-
- //将套接字调整为监听模式
- if(listen(sfd,128) < 0)
- {
- ERR_MSG("listen");
- return -1;
- }
- printf("listen success\n");
-
- int judge;
- ssize_t len = 0;
- int newfd=-1,maxfd=sfd;
- char buf[128] = ""; //字符串搬运工
- struct sockaddr_in cin;
- struct sockaddr_in clidata[1024]; //创建数组来保存newfd的cin,防止多个客户端覆盖地址信息
- socklen_t addrlen=sizeof(cin);
-
- fd_set readfds,tmpfds;
- FD_ZERO(&readfds);
- FD_SET(0,&readfds);
- FD_SET(sfd,&readfds);
-
- while(1)
- {
- tmpfds = readfds;
- //如果没有文件描述符准备就绪则阻塞,如果有则数组中只剩下已经准备就绪的文件描述符
- judge=select(maxfd+1,&tmpfds,NULL,NULL,NULL);
- if(judge < 0)
- {
- ERR_MSG("select");
- return -1;
- }
- else if(0 == judge)
- {
- printf("time out\n");
- return -1;
- }
- for(int i=0;i<=maxfd;i++)
- {
- if(FD_ISSET(i,&tmpfds) == 0)
- continue;
- if(0 == i )
- {
- //当文件描述符为0时,表示终端输入有数据
- printf("触发终端输入事件\n");
- bzero(buf,sizeof(buf));
- fgets(buf,sizeof(buf),stdin);
- buf[strlen(buf)-1]=0;
- printf("buf = %s\n",buf);
- /*
- if(FD_ISSET(newfd,&readfds))
- {
- if(send(newfd,buf,sizeof(buf),0)<0)
- {
- ERR_MSG("send");
- return -1;
- }
- printf("send success\n");
- }
- */
- }else if(sfd == i)
- {
- //当文件描述符为sfd时,表示有客户端连接
- printf("触发客户端连接事件\n");
- if((newfd = accept(sfd,(struct sockaddr*)&cin,&addrlen)) < 0)
- {
- ERR_MSG("accept");
- return -1;
- }
- printf("[%s:%d]客户端连接成功 newfd = %d\n",\
- inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
- //将对应文件描述符的地址信息保存到数组对应下标中
- clidata[newfd] = cin;
- //把newfd加入监听队列中
- FD_SET(newfd,&readfds);
- maxfd = maxfd>newfd?maxfd:newfd;
- }else{
- bzero(buf,sizeof(buf));
- len = recv(i,buf,sizeof(buf),0);
- if(len < 0)
- {
- ERR_MSG("recv");
- return -1;
- }else if(0 == len)
- {
- printf("[%s:%d]客户端已下线,newfd = %d\n",\
- inet_ntoa(clidata[i].sin_addr),ntohs(clidata[i].sin_port),i);
-
- //关闭文件描述符
- close(i);
- //将文件描述符从队列中剔除
- FD_CLR(i,&readfds);
- //更新最大文件描述符
- while(FD_ISSET(maxfd,&readfds) == 0 && (maxfd--) >= 0);
- continue;
- }
- printf("[%s:%d]接收成功,newfd = %d:buf = %s\n",\
- inet_ntoa(clidata[i].sin_addr),ntohs(clidata[i].sin_port),i,buf);
-
- strcat(buf,">-<");
- if(send(i,buf,sizeof(buf),0) < 0)
- {
- ERR_MSG("send");
- return -1;
- }
- printf("send success\n");
- }
- }
- }
- close(sfd);
- return 0;
- }
二、select的客户端:
- #include <myhead.h>
-
- #define ERR_MSG(msg) do{\
- fprintf(stderr,"__%d__\n",__LINE__);\
- perror(msg);\
- }while(0)
-
- #define IP "192.168.114.110" //服务器IP
- #define PORT 8888 //服务器端口号
- int main(int argc, const char *argv[])
- {
- //创建流式套接字
- int cfd;
- if((cfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
- {
- ERR_MSG("socket");
- return -1;
- }
- printf("socket success cfd = %d",cfd);
-
- //非必须绑定
-
- //填充地址信息结构体给connect使用
- struct sockaddr_in sin;
- sin.sin_family = AF_INET;
- sin.sin_port = htons(PORT); //服务器端口号
- sin.sin_addr.s_addr = inet_addr(IP); //服务器IP
-
- if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
- {
- ERR_MSG("connect");
- return -1;
- }
- printf("[%s:%d]服务器绑定成功\n",IP,PORT);
-
- int judge;
- ssize_t len = 0;
- char buf[128]="";
-
- fd_set readfds,tmpfds;
- FD_ZERO(&readfds);
- FD_SET(0,&readfds);
- FD_SET(cfd,&readfds);
-
- while(1)
- {
- tmpfds = readfds;
- judge = select(cfd+1,&tmpfds,NULL,NULL,NULL);
- if(judge < 0)
- {
- ERR_MSG("select");
- return -1;
- }else if(0 == judge)
- {
- printf("time out\n");
- return -1;
- }
- if(FD_ISSET(0,&readfds)) //写事件触发,终端输入给服务器发送
- {
- printf("触发写事件\n");
- bzero(buf,sizeof(buf));
- fgets(buf,sizeof(buf),stdin);
- buf[strlen(buf)-1]=0;
- if(send(cfd,buf,sizeof(buf),0) < 0)
- {
- ERR_MSG("send");
- return -1;
- }
- printf("send success buf=%s\n",buf);
- }
- if(FD_ISSET(cfd,&readfds))
- {//读时间触发,从服务器读取数据
- printf("触发读事件\n");
- bzero(buf,sizeof(buf));
- if((len = recv(cfd,buf,sizeof(buf),0)) < 0)
- {
- ERR_MSG("recv");
- return -1;
- }
- else if(0 == len)
- {
- printf("[%s:%d]服务器已下线\n",IP,PORT);
- break;
- }
- printf("recv success buf=%s\n",buf);
- }
- }
- close(cfd);
- return 0;
- }