zoukankan      html  css  js  c++  java
  • 4. 基本socket函数

    一、创建socket

    /*  创建一个socket  */
    int socket(int family, int type, int protocol);
    
    /*  参数说明  */ 
    // domain:使用哪个底层协议族
    // type:指定服务类型
    // protocol:使用哪个协议 
    

    1. type参数指定的服务类型有SOCK_STREAM服务(流服务)和SOCK_DGRAM服务(数据报服务)

    • 对TCP/IP协议族而言,其值取SOCK_STREAM表示传输层使用TCP协议,取SOCK_DGRAM表示传输层使用UDP协议

    补:type参数可以接受上述服务类型与下面两个重要的标志相与的值:SOCK_NONBLOCK和SOCK_CLOEXEC。它们分别表示将新创建的socket设为非阻塞的,以及用fork调用创建子进程时在子进程中关闭该socket

    2. protocol参数一般都设置为0,表示使用默认协议

    • 因为它是在前两个参数构成的协议集合下,再选择一个具体的协议。而前两个参数已经完全决定了它的值。

    在UNIX/Linux下,所有东西都是文件,socket也不例外,它就是可读、可写、可控制、可关闭的文件描述符

    二、给socket命名——将socket与socket地址绑定

    /* 将一个socket与socket地址绑定 */
    int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
    
    /*  参数说明  */ 
    // myaddr:其所指的socket地址分配给未命名的sockfd文件描述符 
    // addrlen:指出该socket地址的长度
    

    1. 服务器程序需要命名socket,这样客户端才能知道该如何连接它;而客户端通常不需要命名socket,而是采用匿名方式(即使用操作系统自动分配的socket地址)

    2. 两种常见的errno是EACCES和EADDRINUSE

    • EACCES:被绑定的地址是受保护的地址,仅超级用户能访问。如普通用户将socket绑定到知名服务端口(端口号为0~1023)上时,bind将返回EACCES错误。
    • EADDRINUSE:被绑定的地址正在使用中。如将socket绑定到一个处于TIME_WAIT状态的socket地址。

    三、监听socket——将一个主动socket转换成被动socket,使服务器可以接受客户连接

    /* 创建一个监听队列以存放待处理的客户连接 */
    int listen(int sockfd, int backlog);
    
    /*  参数说明  */ 
    // backlog:指定内核监听队列的最大长度
    

    1. backlog参数表示处于完全连接状态(ESTABLISHED)的socket的上限

    补:在内核版本2.2之前的Linux中,backlog参数是指所有处于半连接状态(SYN_RCVD)和完全连接状态(ESTABLISHED)的socket上限。

    2. 当监听队列的长度超过backlog时,服务器将不再受理新的客户连接,客户端也将收到ECONNREFUSED错误信息。

    四、接受连接

    /* 从监听队列中接受一个连接 */
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    
    /*  参数说明  */ 
    // addr:指向被接受连接的远端socket地址 
    // addrlen:远端socket地址的长度 
    

    1. 取出已完成连接(ESTABLISH)队列的队首连接,如果该队列为空,那么进程将被投入睡眠(假设socket为默认的阻塞方式)

    补:accept只是从监听队列中取出连接,而不论连接处于何种状态,如该队首连接对应的客户端掉线或提前退出。

    2. accept返回一个新的连接socket,该socket唯一地标识了这个被接受的连接

    • 服务器通过读写该socket来与被接受连接对应的客户端通信。

    五、发起连接——客户端主动与服务器建立连接

    /* 主动与服务器建立连接 */
    int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
    
    /*  参数说明  */ 
    // servaddr:指向接受连接的远端socket地址 
    // addrlen:远端socket地址的长度 
    

    1. sockfd唯一地标识这个发起的连接

    2. 两种常见的errno是ECONNREFUSED和ETIMEDOUT

    • ECONNREFUSED:目标端口不存在,连接被拒绝。
    • ETIMEDOUT:连接超时。

    3. 若connect失败,则该socket不再可用,必须关闭  

    六、关闭连接——关闭连接对应的socket

    /*  关闭文件描述符  */
    int close(int fd);
    
    /*  立即终止连接  */
    int shutdown(int sockfd, int howto);
    
    /*  参数说明  */
    // howto:决定了shutdown的行为,可选值为SHUT_RD、SHUT_WR和SHUT_RDWR 
    

    1. close将fd的引用计数减1,故其并非总能立即关闭一个连接

    2. shutdown能够分别关闭socket上的读或写,或者都关闭

    七、余音绕梁

    1. 客户往往不给socket命名,而是采用匿名形式,那么是如何确定socket地址的呢?

    当调用connect时,内核将根据所用外出网络接口来确定IP地址,并选择一个临时端口作为源端口。

    2. socket被创建后,其往往被假设为一个主动socket,即认为它将发起连接。而服务器往往调用listen使其变为被动socket,使得内核创建监听队列,从而可以接受连接。  

    3. 系统调用与连接队列

    • connect调用将激发TCP的三路握手过程。
    • 当来自客户的SYN到达时,TCP在其半完成连接队列中创建一个新条目,该条目一直保留到三路握手的第三个分节到达或者该条目超时。
    • 如果三路握手正常完成,该条目就从半完成连接队列转移到完全连接队列的队尾
    • 当服务器进程调用accept时,完全连接队列的队头将返回给进程。

      

      

      

      

      

      

  • 相关阅读:
    在wubantu时,用pychram创建django的App时,出现未找到命令
    Anaconda3 打开Navigator报错
    wubantu18.04版,pycharm2.18.3.2永久破解来了,借鉴个位大神的教程破掉的,感谢各位大佬
    找回感觉的练习
    第四次博客作业-结对项目
    第9次作业--接口及接口回调
    第8次作业--继承
    软件工程第三次作业——关于软件质量保障初探
    第7次作业--访问权限、对象使用
    第6次作业--static关键字、对象
  • 原文地址:https://www.cnblogs.com/xzxl/p/9562427.html
Copyright © 2011-2022 走看看