该文主要是用select实现了一个TCP的echo,客户端连接到服务器端,发送数据,服务器端直接回复原数据给客户端。客户端发送quit则服务器终止。
需要注意的是:
1、每次select前最好都要重新设置一下fd_set
2、不要忘记关闭socket
3、将server_sockfd用fcntl设置为非阻塞
4、select最后一个超时参数,0表示不阻塞,-1表示一直阻塞直到事件发送,还有自定义超时时间。
服务器端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/socket.h> #include<sys/types.h> #include<netinet/in.h> #include<arpa/inet.h> #include <sys/fcntl.h> void select_test(int port, int backlog) { int rcd; int new_cli_fd; int maxfd; socklen_t socklen, server_len; int ci; int watch_fd_list[backlog + 1]; for (ci = 0; ci <= backlog; ci++) watch_fd_list[ci] = -1; int server_sockfd; //建立socket,类型为TCP流 server_sockfd = socket(AF_INET, SOCK_STREAM, 0); if (server_sockfd == -1) { printf("create server_socket error!\n"); exit(1); } //设为非阻塞 if (fcntl(server_sockfd, F_SETFL, O_NONBLOCK) == -1) { printf("Set server socket nonblock failed\n"); exit(1); } struct sockaddr_in server_sockaddr; memset(&server_sockaddr, 0, sizeof(server_sockaddr)); server_sockaddr.sin_family = AF_INET; server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); //设置监听端口 server_sockaddr.sin_port = htons(port); server_len = sizeof(server_sockaddr); //绑定 rcd = bind(server_sockfd, (struct sockaddr *) &server_sockaddr, server_len); if (rcd == -1) { printf("bind port %d error!\n", ntohs(server_sockaddr.sin_port)); exit(1); } //监听 rcd = listen(server_sockfd, backlog); if (rcd == -1) { printf("listen error!\n"); exit(1); } printf("Server is waiting on socket=%d \n", server_sockfd); watch_fd_list[0] = server_sockfd; maxfd = server_sockfd; //初始化监听集合 fd_set watchset; FD_ZERO(&watchset); FD_SET(server_sockfd, &watchset); struct timeval tv; /* 声明一个时间变量来保存时间 */ struct sockaddr_in cli_sockaddr; while (1) { tv.tv_sec = 20; tv.tv_usec = 0; /* 设置select等待的最大时间为20秒*/ //每次都要重新设置集合才能激发事件 FD_ZERO(&watchset); FD_SET(server_sockfd, &watchset); //对已存在到socket重新设置 for (ci = 0; ci <= backlog; ci++) if (watch_fd_list[ci] != -1) { FD_SET(watch_fd_list[ci], &watchset); } rcd = select(maxfd + 1, &watchset, NULL, NULL, &tv); switch (rcd) { case -1: printf("Select error\n"); exit(1); case 0: printf("Select time_out\n"); //超时则清理掉所有集合元素并关闭所有与客户端的socket FD_ZERO(&watchset); for (ci = 1; ci <= backlog; ci++){ shutdown(watch_fd_list[ci],2); watch_fd_list[ci] = -1; } //重新设置监听socket,等待链接 FD_CLR(server_sockfd, &watchset); FD_SET(server_sockfd, &watchset); continue; default: //检测是否有新连接建立 if (FD_ISSET(server_sockfd, &watchset)) { //new connection socklen = sizeof(cli_sockaddr); new_cli_fd = accept(server_sockfd, (struct sockaddr *) &cli_sockaddr, &socklen); if (new_cli_fd < 0) { printf("Accept error\n"); exit(1); } printf("\nopen communication with Client %s on socket %d\n", inet_ntoa(cli_sockaddr.sin_addr), new_cli_fd); for (ci = 1; ci <= backlog; ci++) { if (watch_fd_list[ci] == -1) { watch_fd_list[ci] = new_cli_fd; break; } } FD_SET(new_cli_fd, &watchset); if (maxfd < new_cli_fd) { maxfd = new_cli_fd; } continue; } else {//已有连接的数据通信 //遍历每个设置过的集合元素 for (ci = 1; ci <= backlog; ci++) { //data if (watch_fd_list[ci] == -1) continue; if (!FD_ISSET(watch_fd_list[ci], &watchset)) { continue; } char buffer[128]; //接收 int len = recv(watch_fd_list[ci], buffer, 128, 0); if (len < 0) { printf("Recv error\n"); exit(1); } buffer[len] = 0; //获得客户端的IP地址 struct sockaddr_in sockaddr; getpeername(watch_fd_list[ci], (struct sockaddr*) &sockaddr, &server_len); printf("read data [%s] from Client %s on socket %d\n", buffer,inet_ntoa(sockaddr.sin_addr),watch_fd_list[ci]); //发送接收到到数据 len = send(watch_fd_list[ci], buffer, strlen(buffer), 0); if (len < 0) { printf("Send error\n"); exit(1); } printf("write data [%s] to Client %s on socket %d\n", buffer, inet_ntoa(sockaddr.sin_addr), watch_fd_list[ci]); shutdown(watch_fd_list[ci],2); watch_fd_list[ci] = -1; FD_CLR(watch_fd_list[ci], &watchset); //接收到的是关闭命令 if (strcmp(buffer, "quit") == 0) { for (ci = 0; ci <= backlog; ci++) if (watch_fd_list[ci] != -1) { shutdown(watch_fd_list[ci],2); } printf("\nWeb Server Quit!\n"); exit(0); } } } break; } } } |
1 2 3 4 5 6 |
#define backlog 5 const int port = 8888; int main() { select_test(port,backlog); return 0; } |
客户端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> int client_tcp(char *serIP,in_port_t serPort,char *data); int main() { int port=8888; client_tcp("127.0.0.1",port,"Hello Server1!"); client_tcp("127.0.0.1",port,"Hello Server2!"); client_tcp("127.0.0.1",port,"Hello Server3!"); client_tcp("127.0.0.1",port,"quit"); return 0; } int client_tcp(char *serIP,in_port_t serPort,char *data) { //创建socket int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { printf("socket Error!"); exit(0); } //填充sockaddr_in struct sockaddr_in serAddr; memset(&serAddr, 0, sizeof(serAddr)); serAddr.sin_family = AF_INET; serAddr.sin_port = htons(serPort); int rtn = inet_pton(AF_INET, serIP, &serAddr.sin_addr.s_addr); //或者是 serAddr.sin_addr.s_addr=inet_addr(serIP); if (rtn <= 0) { printf("inet_pton Error!"); exit(0); } printf("目标服务器地址:%s: %d\n", inet_ntoa(serAddr.sin_addr), ntohs(serAddr.sin_port)); printf(" 网络层协议:%s\n", serAddr.sin_family == 2 ? "IPv4" : "IPv6"); printf(" 传输层协议:TCP\n"); //链接服务器 if (connect(sock, (struct sockaddr *) &serAddr, sizeof(serAddr)) < 0) { printf("connect Error!!\n"); exit(0); } //show the other side printf("connected Server %s : %d\n", inet_ntoa(serAddr.sin_addr), ntohs(serAddr.sin_port)); //发送数据 int bufsize = strlen(data); int num = send(sock, data, bufsize, 0); if (num <= 0) { printf("Send Error!!\n"); exit(0); } //接收数据 fputs("Received: ", stdout); char buffer[100]; int n = recv(sock, buffer, 100 - 1, 0); if (n <= 0) { printf("Receive Error!!\n"); exit(0); } else { buffer[n] = '\0'; printf("%s\n", buffer); } //关闭socket close(sock); //exit(0); return 0; } |
发表评论
要发表评论,您必须先登录。