• lv8 嵌入式开发-网络编程开发 17 套接字属性设置


    1 基本概念

    • 设置套接字的选项对套接字进行控制
    • 除了设置选项外,还可以获取选项
    • 选项的概念相当于属性,所以套接字选项也可说是套接字属性
    • 有些选项(属性)只可获取,不可设置;
    • 有些选项既可设置也可获取

    2 选项的级别

    一些选项都是针对一种特定的协议
    一些选项适用于所有类型的套接字
    选项级别(level)的概念

    2.1 常用的级别

    SOL_SOCKET该级别的选项只作用于套接字本身
    SOL_LRLMP该级别的选项作用于IrDA协议
    IPPROTO_IP该级别的选项作用于IPv4协议
    IPPROTO_IPV6该级别的选项作用于IPv6协议
    IPPROTO_RM该级别的选项作用于可靠的多播传输
    IPPROTO_TCP该级别的选项适用于流式套接字
    IPPROTO_UDP该级别的选项适用于数据报套接字

    2.2 SOL_SOCKET的常用选项

    选项名称说明获取/设置
    SO_ACCEPTCONN套接字是否处于监听状态获取
    SO_BROADCAST允许发送广播数据两者都可
    SO_DEBUG允许调试两者都可
    SO_DONTROUTE不查找路由两者都可
    SO_ERROR获得套接字错误获取
    SO_KEEPALIVE保活连接两者都可
    SO_LINGER延迟关闭连接两者都可
    SO_OOBINLINE带外数据放入正常数据流两者都可
    SO_RCVBUF接收缓冲区大小两者都可
    SO_SNDBUF发送缓冲区大小两者都可
    SO_REUSEADDR允许重用本地地址和端口两者都可
    SO_TYPE获得套接字类型获取

    2.3 IPPROTO_IP级别的常用选项

    选项名称说明获取/设置
    IP_OPTIONS获取或设置IP头部内的选项两者都可
    IP_HDRINCL是否将IP头部与数据一起提交给Winsock函数两者都可
    IP_TTLIP TTL相关两者都可

    3获取套接字选项

    3.1 getsockopt函数

    #include           /* See NOTES */
    #include 
    int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
    
    • 1
    • 2
    • 3

    参数
    sockfd:套接字描述符
    level:表示选项的级别
    optname:表示要获取的选项名称
    optval:指向存放接收到的选项内容的缓冲区
    optlen:指向optval所指缓冲区的大小
    函数返回值:
    执行成功返回0,否则返回‒1errno来获取错误码
    常见的错误码:
    EBADF:参数sockfd不是有效的文件描述符
    EFAULT:参数optlen太小或optval所指缓冲区非法
    EINVAL:参数level未知或非法
    ENOPROTOOPT:选项未知或不被指定的协议族所支持
    ENOTSOCK:描述符不是一个套接字描述符

    3.2 示例:获取流套接字和数据报套接字接收和发送的(内核)缓冲区大小

    #include 
    #include 
    #include           
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
     
    int main()
    {
    	int err,s = socket(AF_INET, SOCK_STREAM, 0);//创建流套接字
    	if (s == -1) {
    		printf("Error at socket()\n");
    		return -1;
    	}
    	int su = socket(AF_INET, SOCK_DGRAM, 0); //创建数据报套接字
    	if (s == -1) {
    		printf("Error at socket()\n");
    		return -1;
    	}
    
    	int optVal;
    	int optLen = sizeof(optVal);
    	//获取流套接字接收缓冲区大小
    	if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&optVal,
                       (socklen_t *)&optLen) == -1)
    		printf("getsockopt failed:%d", errno);
    	else
    		printf("Size of stream socket receive buffer: %ld bytes\n", optVal);
    	//获取流套接字发送缓冲区大小
    	if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&optVal,
                       (socklen_t *)&optLen) == -1)
    		printf("getsockopt failed:%d", errno);
    	else 
    		printf("Size of streaming socket send buffer: %ld bytes\n", optVal);
    
    	//获取数据报套接字接收缓冲区大小
    	if (getsockopt(su, SOL_SOCKET, SO_RCVBUF, (char*)&optVal,
                       (socklen_t *)&optLen) == -1)
    		printf("getsockopt failed:%d", errno);
    	else
    		printf("Size of datagram socket receive buffer: %ld bytes\n", optVal);
    	//获取数据报套接字发送缓冲区大小
    	if (getsockopt(su, SOL_SOCKET, SO_SNDBUF, (char*)&optVal,
                       (socklen_t *)&optLen) == -1)
    		printf("getsockopt failed:%d", errno);
    	else
    		printf("Size of datagram socket send buffer:%ld bytes\n", optVal);
    
    	getchar();
    	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

    3.3 示例:获取当前套接字类型

    #include 
    #include 
    #include 
    #include           
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main()
    {
    	int err;
    	int s = socket(AF_INET, SOCK_STREAM, 0); //创建流套接字
    	if (s == -1) {
    		printf("Error at socket()\n");
    		return -1;
    	}
    	int su = socket(AF_INET, SOCK_DGRAM, 0); //创建数据报套接字
    	if (s == -1) {
    		printf("Error at socket()\n");
    		return -1;
    	}
    
    	int optVal;
    	int optLen = sizeof(optVal);
    	//获取套接字s的类型
    	if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&optVal, (socklen_t *)&optLen) == -1)
    		printf("getsockopt failed:%d", errno);
    	else
    	{
    		if (SOCK_STREAM == optVal) // SOCK_STREAM宏定义值为1
    			printf("The current socket is a stream socket.\n"); //当前套接字是流套接字
    		else if (SOCK_DGRAM == optVal) // SOCK_ DGRAM宏定义值为2
    			printf("The current socket is a datagram socket.\n");//当前套接字是数据报套接字
    	}
    	//获取套接字su的类型
    	if (getsockopt(su, SOL_SOCKET, SO_TYPE, (char*)&optVal, (socklen_t *)&optLen) == -1)
    		printf("getsockopt failed:%d", errno);
    	else
    	{
    		if (SOCK_STREAM == optVal)  // SOCK_STREAM宏定义值为1
    			printf("The current socket is a stream socket.\n");
    		else if (SOCK_DGRAM == optVal) // SOCK_ DGRAM宏定义值为2
    			printf("The current socket is a datagram socket.\n");
    	}
    	getchar();
    	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

    3.4 示例:判断套接字是否处于监听状态

    #include 
    #include 
    #include 
    #include 
    #include           
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
     
    typedef struct sockaddr Addr;
    typedef struct sockaddr_in Addr_in;
    
    #define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
    
    int main(int argc, char *argv[])
    {
            Addr_in service;
            if(argc < 3)
            {
                    printf("%s[ADDR][PORT]\n", argv[0]);
                    exit(0);
            }
            int s = socket(AF_INET, SOCK_STREAM, 0); //创建一个流套接字
            if (s == -1) 
                    ErrExit("socket");
            //允许地址的立即重用
            char on = 1;
            setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    
            service.sin_family = AF_INET;
            service.sin_addr.s_addr = inet_addr(argv[1]);
            service.sin_port = htons( atoi(argv[2]) );
            if (bind(s, (Addr*)&service, sizeof(service)) == -1) //绑定套接字
                    ErrExit("bind");
            int optVal;
            int optLen = sizeof(optVal);
            //获取选项SO_ACCEPTCONN的值
            if (getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char*)&optVal, (socklen_t*)&optLen) == -1)
                    printf("getsockopt failed:%d",errno);
            else printf("Before listening, The value of SO_ACCEPTCONN:%d, The socket is not listening\n", optVal);
    
            // 开始侦听
            if (listen(s, 100) == -1)
                    ErrExit("listen");
            //获取选项SO_ACCEPTCONN的值
            if (getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char*)&optVal, (socklen_t*)&optLen) == -1)
                    ErrExit("getsockopt");
            else printf("After listening,The value of SO_ACCEPTCONN:%d, The socket is listening\n", optVal);
            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

    4 设置套接字选项

    4.1 setsockopt函数

    int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
    
    • 1

    参数
    sockfd:套接字描述符
    level:表示选项的级别
    optname:表示要获取的选项名称
    optval:指向存放接收到的选项内容的缓冲区
    optlen:指向optval所指缓冲区的大小
    函数返回值:
    执行成功返回0,否则返回‒1errno来获取错误码

    4.2 示例:启用套接字的保活机制**

    #include 
    #include 
    #include 
    #include 
    #include           
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
     
    typedef struct sockaddr Addr;
    typedef struct sockaddr_in Addr_in;
    
    #define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
    
    int main(int argc, char *argv[])
    {
            Addr_in service;
            if(argc < 3)
            {
                    printf("%s[ADDR][PORT]\n", argv[0]);
                    exit(0);
            }
    
            int s = socket(AF_INET, SOCK_STREAM, 0); //创建一个流套接字
            if( s < 0)
                    ErrExit("socket");
    
            char on = 1;
            setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    
            service.sin_family = AF_INET;
            service.sin_addr.s_addr = inet_addr(argv[1]);
            service.sin_port = htons(atoi(argv[2]));
            if (bind(s, (Addr *) &service, sizeof(service)) == -1) //绑定套接字
                    ErrExit("bind");
    
            int optVal = 1;//一定要初始化
            int optLen = sizeof(int);
    
            //获取选项SO_KEEPALIVE的值
            if (getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*)&optVal, (socklen_t *)&optLen) == -1)
                    ErrExit("getsockopt");
            else printf("After listening,the value of SO_ACCEPTCONN:%d\n", optVal);
    
            optVal = 1;
            if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*)&optVal, optLen) != -1)
                    printf("Successful activation of keep alive mechanism.\n");//启用保活机制成功
    
            if (getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*)&optVal, (socklen_t *)&optLen) == -1)
                    ErrExit("getsockopt");
            else printf("After setting,the value of SO_KEEPALIVE:%d\n", optVal);
    
            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

    5 综合示例

    server.c

    #include "net.h"
    #include 
    #define MAX_SOCK_FD 1024
    
    void setKeepAlive (int sockfd, int attr_on, socklen_t idle_time, socklen_t interval, socklen_t cnt)
    {
    	setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE, (const char *) &attr_on, sizeof (attr_on));
    	setsockopt (sockfd, SOL_TCP, TCP_KEEPIDLE, (const char *) &idle_time, sizeof (idle_time));
    	setsockopt (sockfd, SOL_TCP, TCP_KEEPINTVL, (const char *) &interval, sizeof (interval));
    	setsockopt (sockfd, SOL_TCP, TCP_KEEPCNT, (const char *) &cnt, sizeof (cnt));
    }
    
    int main(int argc, char *argv[])
    {
    	int i, ret, fd, newfd;
    	fd_set set, tmpset;
    	Addr_in clientaddr;
    	socklen_t clientlen = sizeof(Addr_in);
    	/*检查参数,小于3个 直接退出进程*/
    	Argment(argc, argv);
    	/*创建已设置监听模式的套接字*/
    	fd = CreateSocket(argv);
    
    	FD_ZERO(&set);
    	FD_ZERO(&tmpset);
    	FD_SET(fd, &set);
    	while(1){
    		tmpset = set;
    		if( (ret = select(MAX_SOCK_FD, &tmpset, NULL, NULL, NULL)) < 0){
    			perror("select");
    			getchar();
    		}
    		if(FD_ISSET(fd, &tmpset) ){
    			/*接收客户端连接,并生成新的文件描述符*/
    			if( (newfd = accept(fd, (Addr *)&clientaddr, &clientlen) ) < 0){
    				perror("accept");
    				getchar();
    			}
    #if 1
    			int keepAlive = 1;			//设定KeepAlive
    			int keepIdle = 5;			//开始首次KeepAlive探测前的TCP空闭时间
    			int keepInterval = 5;		//两次KeepAlive探测间的时间间隔
    			int keepCount = 3;			//判定断开前的KeepAlive探测次数
    			setKeepAlive (newfd, keepAlive, keepIdle, keepInterval, keepCount);
    #endif
    
    			printf("[%s:%d]已建立连接\n", 
    					inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
    			FD_SET(newfd, &set);
    		}else{ //处理客户端数据
    			for(i = fd + 1; i < MAX_SOCK_FD; i++){
    				if(FD_ISSET(i, &tmpset)){
    					if( DataHandle(i) <= 0){
    						if( getpeername(i, (Addr *)&clientaddr, &clientlen) )
    							perror("getpeername");
    						printf("[%s:%d]断开连接\n", 
    								inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
    						FD_CLR(i, &set);
    						close(i);
    					}
    				}
    			}
    		}
    	}
    	close(fd);
    	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

    socket.c

    #include "net.h"
    
    void Argment(int argc, char *argv[]){
    	if(argc < 3){
    		fprintf(stderr, "%s\n", argv[0]);
    		exit(0);
    	}
    }
    int CreateSocket(char *argv[]){
    	/*创建套接字*/
    	int fd = socket(AF_INET, SOCK_STREAM, 0);
    	if(fd < 0)
    		ErrExit("socket");
    	/*允许地址快速重用*/
    	int flag = 1;
    	if( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag) ) )
    		perror("setsockopt");
    	/*设置通信结构体*/
    	Addr_in addr;
    	bzero(&addr, sizeof(addr) );
    	addr.sin_family = AF_INET;
    	addr.sin_port = htons( atoi(argv[2]) );
    	/*绑定通信结构体*/
    	if( bind(fd, (Addr *)&addr, sizeof(Addr_in) ) )
    		ErrExit("bind");
    	/*设置套接字为监听模式*/
    	if( listen(fd, BACKLOG) )
    		ErrExit("listen");
    	return fd;
    }
    int DataHandle(int fd){
    	char buf[BUFSIZ] = {};
    	Addr_in peeraddr;
    	socklen_t peerlen = sizeof(Addr_in);
    	if( getpeername(fd, (Addr *)&peeraddr, &peerlen) )
    		perror("getpeername");
    	int ret = recv(fd, buf, BUFSIZ, 0);
    	if(ret < 0)
    		perror("recv");
    	if(ret > 0){
    		printf("[%s:%d]data: %s\n", 
    				inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);
    	}
    	return ret;
    }
    
    • 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

    net.h

    `#ifndef _NET_H_
    #define _NET_H_
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    typedef struct sockaddr Addr;
    typedef struct sockaddr_in Addr_in;
    #define BACKLOG 5
    #define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)
    
    void Argment(int argc, char *argv[]);
    int CreateSocket(char *argv[]);
    int DataHandle(int fd);
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    通过wireshark查看设置keepalive的包
    在这里插入图片描述

    6 练习

    编程实现带保活连接功能的TCP代码,要求开始首次KeepAlive探测前的TCP空闭时间为3秒,两次KeepAlive探测间的时间间隔为3次,判定断开前的KeepAlive探测次数为7次。提交代码和完成通信的截图
    注意:部分操作系统需要添加额外头文件 netinet/tcp.h

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define MAX_SOCK_FD 1024
    #define BACKLOG 5
    
    #define ErrExit(msg) do{perror(msg); exit(EXIT_FAILURE);} while(0)
    
    void SetKeepAlive(int sockfd,int attr_on, socklen_t idle_time, socklen_t interval, socklen_t cnt)
    {
    	setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (const char *) &attr_on, sizeof(attr_on));
    	setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, (const char *) &idle_time, sizeof(idle_time));
    	setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (const char *) &interval, sizeof(interval));
    	setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (const char *) &cnt, sizeof(cnt));
    }
    
    int DataHandle(int fd)
    {
    	char buf[BUFSIZ] = {};
    	int ret;
    	struct sockaddr_in peeraddr;
    	socklen_t peerlen = sizeof(struct sockaddr_in);
    	if(getpeername(fd, (struct sockaddr *)&peeraddr, &peerlen) )
    		perror("getpeername");
    	
    	ret = recv(fd, buf, BUFSIZ, 0);
    	if(ret < 0)
    	{
    		perror("recv");
    	}
        if( ret > 0)
    	{
    		printf("[%s:%d]data: %s\n", 
    				inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);
    	}
    	return ret;
    }
    
    int main(int argc,char *argv[])
    {
    	int fd, new_fd, i ,ret;
    	fd_set set, tmpset;
    	struct sockaddr_in addr, client_addr;
    	socklen_t clientlen = sizeof(client_addr);
    
    	
    	int flag = 1;
    
    	if(argc < 3)
    	{
    		printf("%s  \n",argv[0]);
    		exit(0);
    	}
    
    	//create socket
    	fd = socket(AF_INET, SOCK_STREAM, 0);
    	if(fd < 0)
    	{
    		ErrExit("socket");
    	}
    
    	//avoids the error of ports being occupied
    	if( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag) ) )
    	{
    		perror("setsockopt");
    	}
    
    	//init struct sockaddr_in
    	memset(&addr, 0, sizeof(addr));
    	addr.sin_family = AF_INET;
    	addr.sin_port = htons( atoi(argv[2]));
    	if (inet_aton(argv[1], &addr.sin_addr) == 0)
    	{
    		printf("Invalid address\n");
    		exit(EXIT_FAILURE);
    	}
    	
    	
    	
    	//bind
    	if(bind(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == -1)
    	{
    		ErrExit("bind");
    	}
    
    	//listen
    	if(listen(fd, BACKLOG) == -1)
    	{
    		ErrExit("listen");
    	}
    
    	//select
    	FD_ZERO(&set);
    	FD_ZERO(&tmpset);
    	FD_SET(fd, &set);
    	while(1)
    	{
    		tmpset = set;
    		if((ret =  select(MAX_SOCK_FD, &tmpset,NULL,NULL,NULL)) < 0)
    		{
    			ErrExit("select");
    		}
    		if(FD_ISSET(fd, &tmpset) > 0)
    		{
    			new_fd = accept(fd,(struct sockaddr *)&client_addr,&clientlen);
    			if(new_fd < 0)
    			{
    				perror("accept");
    			}
    
    #if 1
    			int keepAlive = 1;
    			int keepIdle = 3;
    			int keepInterval = 3;
    			int keepCount = 7;
    			SetKeepAlive(new_fd, keepAlive, keepIdle, keepInterval, keepCount);
    #endif 
    			printf("[%s:%d]connected\n",inet_ntoa(client_addr.sin_addr),\
    										ntohs(client_addr.sin_port));
    			FD_SET(new_fd, &set);
    		}
    		else //if(FF_ISSET(fd, &tmpset < 0)  //handle client
    		{
    			for(i = fd + 1; i < MAX_SOCK_FD; i++)
    			{
    				// can read
    				if(FD_ISSET(i,&tmpset))
    				{
    					if(DataHandle(i) <= 0)
    					{
    						if(getpeername(i,(struct sockaddr *)&client_addr,&clientlen))			
    							perror("getpeername");
    						printf("[%s:%d]disconnected\n",inet_ntoa(client_addr.sin_addr),\
    														ntohs(client_addr.sin_port));
    						FD_CLR(i,&set);  
    
    					}
    				}
    			}
    		}
    	}
        close(fd);
    
    	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
    • 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
  • 相关阅读:
    X86_64 栈和函数调用
    vue-danmak 弹幕交互组件
    论文解读:(VPT)Visual Prompt Tuning
    vue3使用router的时候出现问题
    jQuery入门
    用友第五届开发者大赛初赛晋级公示,复赛火热进行中!
    PostGIS导入shp文件报错:dbf file (.dbf) can not be opened.
    javascript利用xhr对象实现http流的comet轮循,主要是利用readyState等于3的特点
    关于JVM的参数类型
    亚马逊API接口
  • 原文地址:https://blog.csdn.net/m0_60718520/article/details/133802481