#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include <stdlib.h>#include <unistd.h>#include <arpa/inet.h>#include <netinet/in.h>#include <errno.h>#include <string.h>#include <ctype.h>#include <sys/select.h>int main(){ // 创建监听套接字 int lfd = socket(AF_INET, SOCK_STREAM, 0); if (lfd == -1) { perror("socket error"); exit(1); } // 设置端口复用 int opt = 1; setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt)); //IP地址与端口号信息 struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(9317); serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定、监听 int ret = bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); if (ret == -1) { perror("bind error"); exit(1); } ret = listen(lfd, 64); if (ret == -1) { perror("listen error"); exit(1); } // 用来接收客户端ip信息 struct sockaddr_in client_addr; socklen_t cli_addr_len = sizeof(struct sockaddr_in); // select用的两个事件数组 fd_set reads, temps; // 最大的事件fd int max_fd; // 初始化reads事件表 FD_ZERO(&reads); // 设置内核监视监听套接字 FD_SET(lfd, &reads); max_fd = lfd; while (1) { // 复制reads表传参,保留原reads表不变,因为select会修改传进去的表 temps = reads; int ret = select(max_fd + 1, &temps, NULL, NULL, NULL); if (ret < 0) { fprintf(stderr, "select error: %s\n", strerror(errno)); exit(1); } // 监听套接字有事件 if (FD_ISSET(lfd, &temps)) { int cfd; if ((cfd = accept(lfd, (struct sockaddr *)&client_addr, &cli_addr_len)) < 0) { fprintf(stderr, "accept error: %s\n", strerror(errno)); exit(1); } // 新套接字(客户套接字)加入reads表 FD_SET(cfd, &reads); max_fd = max_fd > cfd ? max_fd : cfd; } int k; for (k = lfd + 1; k <= max_fd; k++) { // 客户端有事件,处理 if (FD_ISSET(k, &temps)) { char buff[1024]; int rec_len, i; if ((rec_len = recv(k, buff, sizeof(buff), 0)) < 0) { fprintf(stderr, "read error: %s\n", strerror(errno)); exit(1); } else if (rec_len == 0) { // 客户端关闭连接 close(k); FD_CLR(k, &reads); } else { for (i = 0; i < rec_len; ++i) { buff[i] = toupper(buff[i]); } send(k, buff, rec_len, 0); } } } } close(lfd); return 0;}