- 服务端
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #include <assert.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <vector> #include <string> using namespace std; int main(int argc,char* argv[]) { printf("server start up\n"); if(argc <= 3) { printf("usage:%s ip port backlog\n",basename(argv[0])); return 1; } //IP地址 const char* ip = argv[1]; //端口号 int port = atoi(argv[2]); //内核监听队列的最大长度(完全连接的socket) int backlog = atoi(argv[3]); //创建socket (TIP/IP协议族,流式socket) int server_sockfd = socket(PF_INET,SOCK_STREAM,0); //最大连接数,初始化为server_sockfd int max_fd = server_sockfd; // vector<int> connFds; connFds.reserve(backlog); //TCP/IP协议族的socket地址结构体 struct sockaddr_in server_addr; bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family = AF_INET; //TCP/IPv4的地址族 inet_pton(AF_INET,ip,&server_addr.sin_addr); //将IP地址字符串转换为二进制的整数并赋给addr.sin_server_addr server_addr.sin_port = htons(port); //端口,host to net,将主机字节序(小端)转换为网络字节序(大端) //将文件描述符sock和socket地址关联,仅服务端需要,客户端自动绑定地址 //注意需要强制转换为 struct sockaddr* int ret = bind(server_sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)); assert(ret != -1); //监听 ret = listen(server_sockfd,backlog); assert(ret != -1); //客户端地址信息 struct sockaddr_in client_addr; socklen_t client_addrlength = sizeof(client_addr); char buf[1024]={0}; //文件描述符集合 fd_set read_fds; fd_set exception_fds; FD_ZERO(&read_fds); FD_ZERO(&exception_fds); //超时 // struct timeval timeout; // timeout.tv_sec = 500; //秒 // timeout.tv_usec = 0 ; //微秒 while(1) { FD_SET(server_sockfd,&read_fds); for(int i =0;i<connFds.size();++i) { FD_SET(connFds[i],&read_fds); FD_SET(connFds[i],&exception_fds); } int ret = select(max_fd+1,&read_fds,NULL,&exception_fds,NULL); if( ret == -1) { //printf("selection failure\n"); perror("select"); break; } else if( ret == 0) { perror("timeout"); break; } for(vector<int>::iterator it = connFds.begin();it != connFds.end();) { if( FD_ISSET(*it,&read_fds) ) { memset(buf,0,sizeof(buf)); int ret = recv(*it,buf,sizeof(buf)-1,0); if(ret <= 0) { perror("recv"); close(*it); FD_CLR(*it,&read_fds); printf("A client disconnectd\n"); it = connFds.erase(it); continue; } else { buf[ret] = '\0'; printf("recived:%s\n",buf); for(int i =0;i<connFds.size();++i) { if(connFds[i] != *it) { string str("some one said:"); str.append(buf); int ret = send(connFds[i],str.c_str(),str.length(),0); if(ret<=0) { perror("send"); } } } } } ++it; } for(vector<int>::iterator it = connFds.begin();it != connFds.end();++it) { if(FD_ISSET(*it,&exception_fds)) { memset(buf,0,sizeof(buf)); int ret = recv(*it,buf,sizeof(buf)-1,MSG_OOB); if(ret < 0) { perror("exception"); } else { buf[ret] = '\0'; printf("%s",buf); } } } if( FD_ISSET(server_sockfd,&read_fds) ) { //接受连接,并将被接受的远端sock地址信息保存在第二个参数中 int newfd = accept(server_sockfd,(struct sockaddr*)&client_addr,&client_addrlength); if(newfd < 0) { perror("accept"); close(newfd); return -1; } else { connFds.push_back(newfd); max_fd = newfd; //inet_ntoa(struct addr_in) 将IP地址转换为字符串并返回 //只是从监听队列中取出连接,即使客户端已经断开网络连接也会accept成功 printf("accept client_addr %s\n",inet_ntoa(client_addr.sin_addr)); } } } //关闭连接,实际只是socket的引用-1,必须引用为0才会真正关闭 for(int i= 0;i< connFds.size();++i) { close(connFds[i]); } close(server_sockfd); return 0; }
- 客户端
#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> #include <assert.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <string> #include <iostream> using namespace std; int main(int argc,char* argv[]) { if(argc <= 2) { printf("usage:%s ip port\n",basename(argv[0])); return 1; } const char* ip = argv[1]; int port = atoi(argv[2]); struct sockaddr_in remote_addr; bzero(&remote_addr,sizeof(remote_addr)); remote_addr.sin_family = AF_INET; inet_pton(AF_INET,ip,&remote_addr.sin_addr); remote_addr.sin_port = htons(port); int remote_sockfd = socket(PF_INET,SOCK_STREAM,0); assert(remote_sockfd>=0); //连接 if(connect(remote_sockfd,(struct sockaddr*)&remote_addr,sizeof(struct sockaddr)) < 0) { perror("connect:"); return -1; } else { printf("connect success\n"); } //文件描述符集合 fd_set read_fds; FD_ZERO(&read_fds); FD_SET(remote_sockfd,&read_fds); //add stand input device FD_SET(0,&read_fds); int ret= -1; string str; char buf[1024]={0}; while (1) { FD_SET(remote_sockfd,&read_fds); FD_SET(0,&read_fds);//add stand input device ret = select(remote_sockfd+1,&read_fds,NULL,NULL,NULL); if(ret < 0) { perror("select"); } if(FD_ISSET(remote_sockfd,&read_fds)) { ret = recv(remote_sockfd,buf,sizeof(buf),0); if(ret > 0) { str.clear(); buf[ret] = '\0'; str.append(buf); cout<<str<<endl; } } if(FD_ISSET(0,&read_fds)) { memset(buf,0,sizeof(buf)); scanf("%s",buf); ret = send(remote_sockfd,buf,strlen(buf),0); if(ret<=0) { perror("send"); } else { str.clear(); str = str+"send: "+buf+"success\n"; cout<<str; } } } close(remote_sockfd); }