思维导图
练习题
1>TCP传输使用IO多路复用select完成客户端
#include <myhead.h>
#define SER_PORT 8888
#define SER_IP "192.168.125.15"
#define CLI_PORT 9999
#define CLI_IP "192.168.125.15"
int main(int argc, char const *argv[])
{//创建用于连接的套接字int cfd = socket(AF_INET, SOCK_STREAM, 0);if (cfd == -1){perror("socket error");return -1;}//给套接字绑定端口IPstruct sockaddr_in cin;cin.sin_family = AF_INET;cin.sin_port = htons(CLI_PORT);cin.sin_addr.s_addr = inet_addr(CLI_IP);//绑定,可选if (bind(cfd, (struct sockaddr *)&cin, sizeof(cin)) == -1){perror("bind error");return -1;}puts("bind success");//连接服务器//填充服务器地址结构体struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(SER_PORT);sin.sin_addr.s_addr = inet_addr(SER_IP);if (connect(cfd, (struct sockaddr *)&sin, sizeof(sin)) == -1){perror("bind sin error");return -1;}puts("connect success");//阻塞客户端int ret;fd_set fd;FD_ZERO(&fd);FD_SET(0, &fd);FD_SET(cfd, &fd);ret = select(cfd + 1, &fd, NULL, NULL, NULL);char buf[128] = "", buf1[128] = "";//客户端收发操作while (1){memset(buf, 0, sizeof(buf));memset(buf1, 0, sizeof(buf1));//接收服务器消息事件触发if (FD_ISSET(cfd, &fd)){if (recv(cfd, buf1, sizeof(buf1), 0) < 0){perror("recv error");return -1;}printf("%s\n", buf1);continue;}//发送事件触发if (FD_ISSET(0, &fd)){fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';if (strcmp(buf, "quit") == 0)break;if (send(cfd, buf, strlen(buf), 0) < 0){perror("send error");return -1;}continue;}}
END://关闭套接字close(cfd);return 0;
}
2>TCP传输实现IO多路复用poll的服务器端
#include <myhead.h>
#define PORT 8888
#define IP "192.168.125.15"
#define OPEN_MAX 10
int main(int argc, char const *argv[])
{//创建tcp监听套接字int sockfd = socket(AF_INET, SOCK_STREAM, 0);//2.绑定sockfdstruct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(PORT);sin.sin_addr.s_addr = inet_addr(IP);if (bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) == -1){perror("bind error");return -1;}puts("bind success");//监听listenif (listen(sockfd, 128) == -1){perror("listen error");return -1;}puts("listen success");//poll相应参数准备struct pollfd pfd[OPEN_MAX];int i = 1, maxi = 1;//初始化poll结构中的文件描述符fdfor (; i < OPEN_MAX; i++)pfd[i].fd = -1;pfd[0].fd = 0;pfd[0].events = POLLIN;pfd[1].fd = sockfd;pfd[1].events = POLLIN;//对已连接的客户端的数据处理while (1){//阻塞检测集合中是否有事件产生,-1表示一直阻塞int ret = poll(pfd, maxi + 1, -1);struct sockaddr_in cin;socklen_t socklen = sizeof(cin);//检测0号描述符if (pfd[0].revents == POLLIN){//终端输入char buf[128] = "";scanf("%s", buf);if (strcmp(buf, "quit") == 0){break;}}//监测sockfd是否存在连接if (pfd[1].revents == POLLIN){int res = 0;//获取客户端res = accept(sockfd, (struct sockaddr *)&cin, &socklen);printf("[%s:%d]发来连接请求\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));//将提取到的res放入poll结构体数组中,以便于监测for (i = 2; i < OPEN_MAX; i++){if (pfd[i].fd < 0){pfd[i].fd = res;pfd[i].events = POLLIN;break;}}//maxi更新if (i > maxi)maxi = i;//如果没有就绪的描述符,就继续poll监测,否则继续向下看if (--res <= 0)continue;}//继续响应就绪的描述符for (i = 2; i <= maxi; i++){if (pfd[i].revents == POLLIN){int len = 0;char buf[128] = "";//接受客户端数据if ((len = recv(pfd[i].fd, buf, sizeof(buf), 0)) < 0){perror("recv error");return -1;}else if (len == 0) //客户端关闭连接{puts("客户端下线");close(pfd[i].fd);pfd[i].fd = -1;}else{printf("[%s:%d]%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);//正常接收到服务器的数据strcat(buf, "^.^");send(pfd[i].fd, buf, sizeof(buf), 0);}//所有的就绪描述符处理完了,就退出当前的for循环,继续poll监测if (--ret <= 0)break;}}}close(sockfd);return 0;
}