< 0) {sys_err("select error");}if (FD_ISSET(listenfd, &rset)) {// 说明有新的客户端链接请求clie_addr_len = sizeof(clie_addr);connfd = accept(listenfd, (struct sockaddr *)&clie_addr, &clie_addr_len);// accept不会阻塞FD_SET(connfd, &allset);// 向监控文件描述符集合allset添加新的文件描述法connfdif (maxfd < connfd) {maxfd = connfd;}if (0 == --nready) {continue;}}for (i = listenfd + 1; i <= maxfd; i++) {// 检测哪个客户端有数据就绪if (FD_ISSET(i, &rset)) {if ((n = read(i, buf, sizeof(buf))) == 0) {// 当客户端关闭链接时,服务器也关闭对应链接close(i);FD_CLR(i, &allset);}else if (n > 0) {for (j = 0; j < n; j++) {buf[j] = toupper(buf[j]);}write(i, buf, n);}}}}close(listenfd);return 0;}
2.5 linux和通信
代码
#define WIN32_LEAN_AND_MEAN#define _WINSOCK_DEPRECATED_NO_WARNINGS#include #include #include #pragma comment(lib, "ws2_32.lib")using namespace std;int main(){WORD ver = MAKEWORD(2, 2);// 版本号,启动windows socket 2.x环境WSADATA dat;// 数据结构,用来存储被WSAStartup函数调用后返回的Windows Sockets数据 。// 它包含Winsock.dll执行的数据 。WSAStartup(ver, &dat);// 1.建立一个socketSOCKET _sock = socket(AF_INET, SOCK_STREAM, 0);// 2.连接服务器sockaddr_in _sin = {};_sin.sin_family = AF_INET;_sin.sin_port = htons(6666);_sin.sin_addr.S_un.S_addr = inet_addr("192.168.244.137");int ret = connect(_sock, (sockaddr*)&_sin, sizeof(sockaddr_in));if (SOCKET_ERROR == ret) {cout << "绑定网络端口失败" << endl;}else {cout << "绑定网络端口成功" << endl;}char recvBuf[256] = {};int nlen = recv(_sock, recvBuf, 256, 0);if (nlen > 0) {cout << "接收到数据: " << recvBuf << endl;}// 4.关闭套接字closesocketclosesocket(_sock);getchar();// 清除windows socket环境WSACleanup();return 0;}
拓展一下思路,其他的 TCP 通信同样可以和服务端连接
2.的优缺点
1、缺点
监听上限受文件描述符限制,最大 1024 个
检测满足条件的 fd,自己添加业务逻辑提高小 。提高了编码难度 。
2、优点
跨平台
2.7添加一个自己定义数组提高效率
#include #include #include #include #include #include #include "wrap.h"#define SERV_PORT 6666int main(int argc, char *argv[]){int i, j, n, maxi;int nready, client[FD_SETSIZE];// 自定义数组client, 防止遍历1024个文件描述符FD_SETSIZE默认为1024 */int maxfd, listenfd, connfd, sockfd;char buf[BUFSIZ], str[INET_ADDRSTRLEN];// #define INET_ADDRSTRLEN 16 struct sockaddr_in clie_addr, serv_addr;socklen_t clie_addr_len;fd_set rset, allset;// rset 读事件文件描述符集合 allset用来暂存listenfd = Socket(AF_INET, SOCK_STREAM, 0);int opt = 1;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));bzero(&serv_addr, sizeof(serv_addr));serv_addr.sin_family= AF_INET;serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);serv_addr.sin_port= htons(SERV_PORT);Bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));Listen(listenfd, 128);maxfd = listenfd;// 起初 listenfd 即为最大文件描述符maxi = -1;// 将来用作client[]的下标, 初始值指向0个元素之前下标位置for (i = 0; i < FD_SETSIZE; i++) {client[i] = -1;// 用-1初始化client[]}FD_ZERO(&allset);FD_SET(listenfd, &allset);// 构造select监控文件描述符集while (1) {rset = allset;// 每次循环时都重新设置select监控信号集 nready = select(maxfd+1, &rset, NULL, NULL, NULL);// 21--lfd1--connfdif (nready < 0) {perr_exit("select error");}if (FD_ISSET(listenfd, &rset)) {// 说明有新的客户端链接请求clie_addr_len = sizeof(clie_addr);connfd = Accept(listenfd, (struct sockaddr *)&clie_addr, &clie_addr_len);// Accept 不会阻塞 */printf("received from %s at PORT %d\n",inet_ntop(AF_INET, &clie_addr.sin_addr, str, sizeof(str)),ntohs(clie_addr.sin_port));for (i = 0; i < FD_SETSIZE; i++) if (client[i]