zoukankan      html  css  js  c++  java
  • accept的一个小陷阱

    先看下面的代码:

    监听127.0.0.1 : 5563 ,如果有连接,就输出这个客户端的IP、端口和连接描述符。

    #include <stdio.h>
    #include <arpa/inet.h>
    
    int main(int argc,char** argv){
            int  _socket = 0 ;
            struct sockaddr_in addr_server,addr_client;
    
            _socket = socket(AF_INET, SOCK_STREAM, 0);
    
            addr_server.sin_family = AF_INET;
            addr_server.sin_addr.s_addr = htonl(INADDR_ANY);
            addr_server.sin_port = htons(5563);
    
            int ret = bind(_socket,(struct sockaddr *)&addr_server, sizeof(addr_server));
            ret = listen(_socket, 16);
            int length ;
            while(1){
                    int fd = accept(_socket, (struct sockaddr *)&addr_client, &length);
                    if (fd == -1) {
                            break;
                    }
                    printf("IP:%s.Port:%d.Fd:%d Connect!\n",inet_ntoa(addr_client.sin_addr),addr_client.sin_port,fd);
            }
            return 0;
    }

    在执行gcc -o accept accept.c之后,分两次在客户端用telnet进行连接,输出如下:

    [root@localhost network]# ./accept 
    IP:255.127.0.0.Port:22011.Fd:4 Connect!
    IP:127.0.0.1.Port:25237.Fd:5 Connect!


    注意:第一次的IP输出的并不是127.0.0.1,而是一个其它的IP地址,事实上第一次在每次启动的时候,所输出的IP都不相同。

    accept定义如下:

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);


    参数说明 

    1)sockfd 。通过调用socket函数所返回的socket 文件描述符。

    2)addr。sockaddr结构,这个参数在accept成功返回之后,将会被socket连接另一端的地址填充,也就是会包含客户端的IP和端口信息。

    3)addrlen。这是一个引用类型的参数,调用accept的人必须要对这个值以初始为第二个参数addr的结构所包含的字节数大小。当accept返回之后,它将包含从另一端返回的实际字节数大小。

    那么问题就出来了,在前面的代码中第一次调用 accept时,并没有指定length参数的值为addr结构体大小,这样内核就会以为这个结构大小为0,因此不足以存储将客户端的信息返回,但在第一次以后,length的值就被内核修改了,改成了真实的结构返回大小,而后每次调用就正常了。

    修改如下:

    #include <stdio.h>
    #include <arpa/inet.h>
    
    int main(int argc,char** argv){
            int  _socket = 0 ;
            struct sockaddr_in addr_server,addr_client;
    
            _socket = socket(AF_INET, SOCK_STREAM, 0);
    
            addr_server.sin_family = AF_INET;
            addr_server.sin_addr.s_addr = htonl(INADDR_ANY);
            addr_server.sin_port = htons(5563);
    
            int ret = bind(_socket,(struct sockaddr *)&addr_server, sizeof(addr_server));
            ret = listen(_socket, 16);
            int length ;
            while(1){
                    length =  sizeof(struct sockaddr_in);
                    int fd = accept(_socket, (struct sockaddr *)&addr_client, &length);
                    if (fd == -1) {
                            break;
                    }
                    printf("IP:%s.Port:%d.Fd:%d %d Connect!\n",inet_ntoa(addr_client.sin_addr),addr_client.sin_port,fd,length);
            }
            return 0;
    }


    运行就正常了:

    [root@localhost network]# ./accept 
    IP:127.0.0.1.Port:26005.Fd:4 16 Connect!
    IP:127.0.0.1.Port:26261.Fd:5 16 Connect!
    IP:127.0.0.1.Port:26517.Fd:6 16 Connect!
    IP:127.0.0.1.Port:26773.Fd:7 16 Connect!


    从结果可以看出,第一次显示的IP也是正确的,然后每次accept返回之后,length的值都为sizeof(struct sockaddr_in),这也是以前为什么从第二次开始就正确了的原因。

  • 相关阅读:
    virtualenv与virtualenvwrapper
    数据类型、变量定义、数据类型转换
    计算机存储单元、标识符
    html单页面中用angular js
    svn客户端访问失败,错误“请求的名称有效,但是找不到请求的类型”的解决
    php 获取某数组中出现次数最多的值(重复最多的值)与出现的次数
    数据库导入时出现“2006
    phpstorm 激活
    取消本地SVN文件夹与服务器的关联
    js实现倒计时函数
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3109122.html
Copyright © 2011-2022 走看看