【探讨】模拟聊天室程序
服务端程序:程序代码:
#include<sys/socket.h> #include<netinet/in.h> #include<string.h> #include<stdio.h> #include<sys/select.h> #include<iostream> using namespace std; #define MAXLEN 1000 int client[FD_SETSIZE]; //用来存放当前以链接的套接字 int maxi; //记录client数组以用的最大下标 int sendToAll(int sockfd, int maxi) { char buff[MAXLEN]; int n; if( (n = read(sockfd, buff, MAXLEN)) == 0) return 0; for(int i=0; i<= maxi; ++i ) { if( client[i] >=0 && client[i] != sockfd) { write(client[i], buff, n); } } return n; } int main() { //创建监听套接字 int listenSockd; if( (listenSockd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ fputs("socket error", stderr); return -1; } //绑定地址和接口 struct sockaddr_in servaddr; bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8888); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(listenSockd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0 ) { fputs("bind error", stderr); return -1; } //开始接听 listen(listenSockd, 10); //初始化client数组和maxi, client数组值为-1表示未用 maxi = -1; for(int i=0; i< FD_SETSIZE; ++i) client[i] = -1; //设置select监听事件 int maxfd = listenSockd+1; fd_set rset, allset; //allset为每次需要监听的事件,rset为监听到的事件 FD_ZERO(&allset); FD_SET(listenSockd, &allset); while(1) { rset = allset; int nready; nready = select(maxfd, &rset, NULL, NULL, NULL); //判断是否有新的连接 if(FD_ISSET(listenSockd, &rset)) { int connfd,i; connfd = accept(listenSockd, NULL, NULL); //找到最前面没有被使用的,然后把新的套接字存入其中, //同时更新allset和maxi for(i = 0; i < FD_SETSIZE; ++i) { if(client[i] < 0) { client[i] = connfd; FD_SET(connfd, &allset); if( connfd >= maxfd ) maxfd = connfd + 1; break; } } if( i > FD_SETSIZE) { fputs("too many clients", stderr); return -1; } if(i > maxi) maxi = i; if(--nready <= 0) continue; } //判断是否有套接字已经准备好读 for(int i=0; i<= maxi; ++i) { if(client[i] < 0 ) continue; if(FD_ISSET(client[i], &rset)) { if( sendToAll(client[i], maxi) == 0 ) { client[i] = -1; FD_CLR(client[i], &allset); shutdown(client[i], SHUT_RDWR); } if(--nready <= 0 ) break; } } } return 0; }
客户端程序:
程序代码:
#include<sys/socket.h> #include<stdio.h> #include<sys/select.h> #include<netinet/in.h> #include<arpa/inet.h> #include<string.h> #include<assert.h> #define MAXLEN 1000 int main(int argc, char *argv[]) { assert( argc >= 2 ); int sockfd; if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fputs("socket error", stderr); return -1; } struct sockaddr_in clientaddr; bzero(&clientaddr, sizeof(clientaddr)); clientaddr.sin_family = AF_INET; clientaddr.sin_port = htons(8888); inet_pton(AF_INET, argv[1], &clientaddr.sin_addr); if( connect(sockfd, (struct sockaddr *)&clientaddr, sizeof(clientaddr)) < 0){ fputs("connect error", stderr); return -1; } int flag = 0; char recvBuff[MAXLEN], sendBuff[MAXLEN]; fd_set rset; FD_ZERO(&rset); while( 1 ) { FD_SET(sockfd, &rset); if( !flag) FD_SET(fileno(stdin), &rset); select(sockfd+1, &rset, NULL, NULL, NULL); if(FD_ISSET(sockfd, &rset)) { int n; if((n = read(sockfd, recvBuff, MAXLEN)) == 0){ if(flag) return 0; else { fputs("read error", stderr); return -1; } } recvBuff[n] = '\0'; fputs(recvBuff, stdout); } if(FD_ISSET(fileno(stdin), &rset)){ int n; if((n = read(fileno(stdin), sendBuff, MAXLEN)) == 0) { flag = 1; FD_CLR(fileno(stdin), &rset); shutdown(sockfd, SHUT_WR); continue; } write(sockfd, sendBuff, n); } } return 0; }