不落辰

知不可乎骤得,托遗响于悲风

0%

网络_socket流程

只记录API关键信息方便快速回忆。API的具体信息还请man。以前初学的时候记录的信息太冗杂了。现在看也不方便看,这回力求精简,痛苦的重写一遍概要。

socket API

server

  • 最基本API使用流程
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //  1. create socket
    int lfd = socket(PF_INET,SOCK_STREAM,0);
    // 2. bind socket with addr
    // 之前要先将protocol、ip、port以网络字节序存储入server_addr
    bind(lfd,(sockaddr*)&server_addr,sizeof server_addr);
    // 3. listen
    listen(lfd,5);
    // 4. accept
    int connfd = accept(fd,(sockaddr*)&cliet_addr,&len);
    // 5. read/write
    int len = read(fd,buf,BUFFER_SIZE-1);
    // 6. close
    close(fd);

    socket地址

  • sockaddr_in :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    struct sockaddr_in
    {
    sa_family sin_family; // protocol :AF_INET
    u_int16_t sin_port; // port :网络字节序
    struct in_addr sin_addr; // ip :IPv4结构体
    };
    struct in_addr
    {
    u_int32_t s_addr; // ip address : 网络字节序
    }
    • 将 port(short) 和 ip(点分十进制字符串) 以网络字节序保存,供给socket使用。
      • 程序员看到的 port 是 : 本地字节序 && short。看到的ip是 本地字节序 && 点分十进制字符串。
      • 将他们以网络字节序存入sockaddr_in
        1
        2
        3
        4
        5
        6
        //  将protocol、ip、port以网络字节序存储入server_addr
        struct sockaddr_in server_addr;
        memset(&server_addr,0,sizeof server_addr);
        server_addr.sin_family = AF_INET; // protocol network
        inet_pton(AF_INET,ip,&server_addr.sin_addr.s_addr); // ip str->network
        server_addr.sin_port = htons(port); // port network

socket

  • 原型
    • int socket(int domain,int type,int protocol);
    • return fd;
  • 使用
    • int listening_fd = socket(PF_INET,SOCK_STREAM,0);

bind

  • 原型:
    • int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    • 将socket地址addr结构体,绑定给sockfd。
  • 使用:
    • bind(listening_fd,(sockaddr*)&server_addr,sizeof server_addr);

listen

  • 原型

    • int listen(int sockfd, int backlog);
    • 创建监听队列以存放待处理客户连接
  • 使用

    • listen(listening_fd,5);
  • 在listen之后listening_fd即变为监听socket,可以接受连接/epoll了。

accept

  • 原型
    • int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    • success : return connection fd;
    • fail : return -1 and set errno
  • 使用
    • int connfd = accept(lfd,(sockaddr*)&cliet_addr,&cliet_len);
    • accept之后即可对connfd进行读写操作
    • 即便client建立连接之后又断开网络或者退出程序,server也可连接
      • accept只是从监听队列中取出连接,而不论连接处于何种状态。

client

  • client socketAPI流程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //  1.  创建socket
    int client_conn_fd = socket(PF_INET, SOCK_STREAM, 0);
    // 2. 发起连接
    // 之前要将要连接的server的protocol、ip、port以网络字节序存储入server_addr
    connect(client_conn_fd, (sockaddr *)&server_address, sizeof server_address);
    // 3. read/write
    send(client_conn_fd, request.c_str(), request.size(), 0);
    // 4. close
    close(client_conn_fd);

    connect

  • 原型

    • int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    • success : return 0
    • fail : return -1 and set errno
  • 使用

    • connect(client_fd, (sockaddr *)&server_address, sizeof server_address);