zoukankan      html  css  js  c++  java
  • socket-单进程阻塞io

    一。创建 socket

    首先引入头文件

    // 提供socket函数及数据结构
    #include <sys/socket.h>

    然后创建 socket 和 返回的文件描述符 lfd

    int lfd;
    lfd = socket(AF_INET,SOCK_STREAM,0);
    声明为
    int     socket(int, int, int);

    第一个参数为地址族协议类型,有

    AF_INET   : ipv4
    AF_INET6  : ipv6
    AF_UNIX   : 本地协议,用在同一台机器上传输

    第二个参数为传输协议,有

    SOCK_STREAM : 按顺序,可靠,完整的流连接,默认 tcp
    SOCK_DGRAM  : 无连接,固定长度,不可靠的数据报,默认 udp
    还有其他的,比如 ping 命令 所使用的 icmp 协议 等

    第三个参数为使用哪些传输协议,0 表示使用默认协议

    返回值为一个文件描述符,错误则返回 -1 

    二。绑定网络地址和端口 bind

    首先引入头文件

    // 定义数据结构sockaddr_in
    #include <netinet/in.h>

    创建 网络地址 和 端口 的输入参数

    /*
     * Socket address, internet style.
     */
    struct sockaddr_in {
        __uint8_t       sin_len;
        sa_family_t     sin_family;    地址族协议类型,和 socket 第一个参数一样
        in_port_t       sin_port;      端口号
        struct  in_addr sin_addr;      ip 地址,需要用到下面的结构体,即 sin_addr.s_addr
        char            sin_zero[8];
    };
    /*
     * Internet address (a structure for historical reasons)
     */
    struct in_addr {
        in_addr_t s_addr;
    };

    初始化上面结构体的输入参数

    struct sockaddr_in sock_server;
    sock_server.sin_family      = AF_INET;
    sock_server.sin_addr.s_addr = htonl(INADDR_ANY);    
    sock_server.sin_port
    = htons(6666);
    htonl 将本地数字IP 字节序 转换为 网络字节序,INADDR_ANY 为有效的本地IP,即 127.0.0.1 和对外的一个IP
    htons 将本地数字端口 字节序转换成 网络字节序,网络一般都是采用大端传输

    对第一步 socket 所返回的 lfd 文件描述符进行绑定 地址 和 端口

    int ret;
    ret = bind(lfd, (struct sockaddr *)&sock_server, sizeof(sock_server));

    声明为

    int     bind(int, const struct sockaddr *, socklen_t)

    第一个参数为需要绑定的文件描述符

    第二个参数为IP和端口的数据结构,需要向上转换为 sockaddr 指针,数据结构为

    /*
     * [XSI] Structure used by kernel to store most addresses.
     */
    struct sockaddr {
        __uint8_t       sa_len;         /* total length */
        sa_family_t     sa_family;      /* [XSI] address family */
        char            sa_data[14];    /* [XSI] addr value (actually larger) */
    };

      sockaddr 细化后 就为 sockaddr_in ,sockaddr * 是个通用指针,这样可以接受多种协议的结构体,而每种协议长度不同,所以要传第三个参数

    第三个参数为第二个参数结构体的长度
    返回值为 0表示成功,-1 表示失败
     
    三。监听绑定后的文件描述符 listen
     ret = listen(lfd, 5);

    声明为

    int     listen(int, int)

    第一个参数为需要监听的文件描述符

    第二个参数为监听的最大连接数,这个是指 三次握手开始 到 三次握手结束 的这段时间的最大连接数,不是通道建立成功后的连接数

    成功返回 0 ,失败返回 -1

    四,接收成功建立通道的连接 accept

    int cfd;
    cfd = accept(lfd, (struct sockaddr *)&sock_server, &client_len);

    声明为

    int     accept(int, struct sockaddr * __restrict, socklen_t * __restrict)

    第一个参数为监听的文件描述符

    第二个参数和 bind 的第二个参数一样,但这个参数是作为传出参数,记录了成连接的 IP 和 端口

    第三个参数为传入传出参数,传人时为 (第二个参数) 通用结构体的大小,传出为 连接成功后 具体结构体 (第二个参数) 的大小 

    失败返回 -1 ,成功 返回和客户端连接成功新的文件描述符

    五。对连接成功的文件描述符进行读写

    char buf[2048];
    int n;
    n = read(cfd, buf, sizeof(buf));
    write(cfd, buf, n);

    六。连接测试

    编译运行服务端,然后连接测试,使用 net connect 命令

     客户端写什么,服务端就回复什么

    代码地址:https://gitee.com/GH16/network

    7. 参考

    https://www.bilibili.com/video/BV1M4411j73S?p=21

  • 相关阅读:
    [leetcode] Weekly Contest 170 Summary
    [Scala] java使用scala的jar包问题:Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Short
    [git] Updates were rejected because the tip of your current branch is behind its remote counterpart.
    [Android] Installation failed due to: ''pm install-create -r -t -S 4590498' returns error 'UNSUPPORTED''
    CTF 常见操作总结
    记项目管理大作业Web项目Mandrian的全流程[其一] 整体分析: 功能划分, 组织结构
    [leetcode] 题解记录 11-20
    [leetcode] 题解记录 1-10
    记一次配置阿里云ECS GPU计算型gn5实例
    shell脚本 入门 —— 符号篇
  • 原文地址:https://www.cnblogs.com/GH-123/p/12873578.html
Copyright © 2011-2022 走看看