TCPselect
代码
服务器
#include<myhead.h>
#include<sqlite3.h>
#define PORT 6666 //端口号
#define IP "192.168.0.104" //IP地址//键盘事件
int jp(fd_set tempfds,int maxfd)
{char buf[128] = ""; //用来接收数据char buf1[128] = ""; //用来接收数据int snfd = -1; //用来接受从终端的文件描述符bzero(buf,sizeof(buf)); //清空字符串int res = scanf("%d %s",&snfd,buf); //从终端读取文件描述符和接收数据while(getchar() != 10); //循环吸收垃圾字符if(res != 2) //判断是否输入了两个数据{printf("输入数据格式错误!\n");return -1;}if(snfd <= 2 || FD_ISSET(snfd,&tempfds) == 0) //判断是否正确输入文件描述符{printf("输入非法文件描述符:%d\n",snfd);return -1;}sprintf(buf1,"%c%c%s",'s',':',buf);if(send(snfd,buf1,sizeof(buf1),0) < 0) //判断是否发送成功{ERR_MSG("send");return -1;}return 0;
}//客户端链接事件
int lj(int sfd,struct sockaddr_in sevecin[1024],fd_set *preadfds,int *maxfd)
{int newfd = -1;struct sockaddr_in cin; //客户端信息结构体socklen_t len = sizeof(cin); //信息结构体真实大小//连接客户端newfd = accept(sfd,(struct sockaddr *)&cin,&len);if(newfd < 0) //判断是否连接成功{ERR_MSG("newfd");return -1;}printf("[%s : %d] 客户端连接成功!\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));sevecin[newfd] = cin; //将新的客户端连接到客户端数组中FD_SET(newfd,preadfds);//将新的文件描述符添加到读集合中*maxfd = *maxfd > newfd ? *maxfd : newfd;//更新最大文件描述符return 0;
}//客户端交互事件
int jh(int fd, struct sockaddr_in sevecin[1024],fd_set *readfds,int *maxfd)
{char buf[128] = ""; //搬运工bzero(buf,sizeof(buf)); //清空字符串//接收ssize_t res = recv(fd,buf,sizeof(buf),0);if(res < 0){ERR_MSG("recv");return -1;}else if(res == 0){printf("[%s : %d]客户端已下线!\n",inet_ntoa(sevecin[fd].sin_addr),ntohs(sevecin[fd].sin_port));close(fd); //关闭文件描述符FD_CLR(fd,readfds);//从读集合中删除该信息while(FD_ISSET(*maxfd,readfds) && (*maxfd)-- >= 0);//更新最大文件描述符return 0;}printf("[%s : %d]: %s\n",inet_ntoa(sevecin[fd].sin_addr),\ntohs(sevecin[fd].sin_port),buf);//发送strcat(buf,"*_*");if(send(fd,buf,sizeof(buf),0) < 0){ERR_MSG("send");return -1;}return 0;
}//主函数
int main(int argc, const char *argv[])
{//创建套接字int sfd = -1;if((sfd = socket(AF_INET,SOCK_STREAM,0)) < 0)//判断是否创建成功{ERR_MSG("socket");return -1;}//端口快速复用int reuse = 1;if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0){ERR_MSG("setsockopt");return -1;}//填充信息结构体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;}//监听if(listen(sfd,128) < 0)//判断是否设置监听成功{ERR_MSG("listen");return -1;}//创建一个读集合fd_set readfds,tempfds;//清空集合FD_ZERO(&readfds);//将需要监测的文件放入到集合中FD_SET(0,&readfds);FD_SET(sfd,&readfds);//记录最大文件描述符int maxfd = sfd;//记录select函数的返回值int s_res;//备份连接成功的客户端信息struct sockaddr_in sevecin[1024];bzero(sevecin,sizeof(sevecin)); //清空数组while(1){FD_ZERO(&tempfds);tempfds = readfds;s_res = select(maxfd+1,&tempfds,NULL,NULL,NULL); //多路复用if(s_res < 0){ERR_MSG("select");return -1;}if(s_res == 0){printf("超时!\n");break;}for(int i = 0; i <= maxfd; i++){if(FD_ISSET(i,&tempfds) == 0){continue;}if(i == 0){//键盘事件jp(readfds,maxfd);}else if(i == sfd){//客户端链接事件lj(sfd,sevecin,&readfds,&maxfd);}else{//客户端交互事件jh(i,sevecin,&readfds,&maxfd);}}}if(close(sfd) < 0){ERR_MSG("close");return -1;}return 0;
}
客户端
#include<myhead.h>
#include<sqlite3.h>
#define PORT 6666 //端口号
#define IP "192.168.0.104" //IP
int main(int argc, const char *argv[])
{//创建流式套接字int cfd = socket(AF_INET,SOCK_STREAM,0);if(cfd < 0) //判断是否创建成功{ERR_MSG("socket");}//填充客户端地址信息struct sockaddr_in cin;cin.sin_family = AF_INET;cin.sin_port = htons(PORT); //端口cin.sin_addr.s_addr = inet_addr(IP); //IP//连接if(connect(cfd,(struct sockaddr *)&cin,sizeof(cin)) < 0){ERR_MSG("connect");return -1;}//定义读集合fd_set readfds,tempfds;FD_ZERO(&readfds); //清空集合FD_SET(0,&readfds); //加入集合FD_SET(cfd,&readfds);char buf[128] = ""; //定义搬运工while(1){tempfds = readfds;bzero(buf,sizeof(buf));//多路复用int s_res = select(cfd+1,&tempfds,NULL,NULL,NULL);if(s_res < 0){ERR_MSG("select");return -1;}if(s_res == 0){printf("超时!\n");break;}//向服务器发送数据if(FD_ISSET(0,&tempfds)){bzero(buf,sizeof(buf));//清空字符串fgets(buf,sizeof(buf),stdin); //从终端获取数据buf[strlen(buf) - 1] = 0; //换行变成'\0'if(send(cfd,buf,sizeof(buf),0) < 0) //发送数据并判断数据是否发送成功{ERR_MSG("send");return -1;}}//从服务器接受数据if(FD_ISSET(cfd,&tempfds)){bzero(buf,sizeof(buf)); //清空字符串int res = recv(cfd,buf,sizeof(buf),0); if(res < 0) //判断是否成功接受{ERR_MSG("recv");return -1;}else if(res == 0) //判断服务器是否下线{printf("服务器下线!\n");break;}printf("%s\n",buf);fflush(stdout);}}if(close(cfd)) //关闭文件描述符并判断是否关闭成功{ERR_MSG("close");return -1;}return 0;
}
现象