Linux网络编程之网络传输

116 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 23 天,点击查看活动详情

一、网络套接字socket

一个文件描述符指向一个套接字(该套接字内部由内核借助两个缓冲区实现。)

注意在通信过程中, 套接字一定是成对出现的。

套接字示意图

套接字.png

二、网络字节序

小端法与大端法

小端法:(pc本地存储) 高位存高地址。地位存低地址。 int a = 0x12345678

大端法:(网络存储) 高位存低地址。地位存高地址。

htonl传输

  • htonl --> 本地--》网络 (IP) 192.168.1.11 --> string --> atoi --> int --> htonl --> 网络字节序

  • htons --> 本地--》网络 (port)

  • ntohl --> 网络--》 本地(IP)

  • ntohs --> 网络--》 本地(Port)

三、IP地址转换函数

  1. int inet_pton(int af, const char *src, void *dst);

    本地字节序(string IP) ---> 网络字节序

    一些参数

    af:AF_INET、AF_INET6

    src:传入,IP地址(点分十进制)

    dst:传出,转换后的 网络字节序的 IP地址。

    返回值

    成功: 1

    异常: 0, 说明src指向的不是一个有效的ip地址。

    失败:-1

  2. const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

    网络字节序 ---> 本地字节序(string IP)

    一些参数

    af:AF_INET、AF_INET6

    src: 网络字节序IP地址

    dst:本地字节序(string IP)

    size: dst 的大小。

    返回值

    成功:dst。

    失败:NULL

四、socket函数

  • #include <sys/socket.h>

    int socket(int domain, int type, int protocol); 创建一个 套接字

    参数

    domain:AF_INET、AF_INET6、AF_UNIX

    type:SOCK_STREAM、SOCK_DGRAM

    protocol: 0

    返回值

    成功: 新套接字所对应文件描述符

    失败: -1 errno

  • #include <arpa/inet.h>

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 给socket绑定一个 地址结构 (IP+port)

    参数

    sockfd: socket 函数返回值

    struct sockaddr_in addr;
    
    addr.sin_family = AF_INET;
    
    addr.sin_port = htons(8888);
    
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
    

    addr: 传入参数(struct sockaddr *)&addr

    addrlen: sizeof(addr) 地址结构的大小。

    返回值

    成功:0

    失败:-1 errno

  • int listen(int sockfd, int backlog); 设置同时与服务器建立连接的上限数。(同时进行3次握手的客户端数量)

    参数

    sockfd: socket 函数返回值

    backlog:上限数值。最大值 128.

    返回值

    成功:0

    失败:-1 errno

  • int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 阻塞等待客户端建立连接,成功的话,返回一个与客户端成功连接的socket文件描述符。

    参数

    sockfd: socket 函数返回值

    addr:传出参数。成功与服务器建立连接的那个客户端的地址结构(IP+port)

    socklen_t clit_addr_len = sizeof(addr);
    

    addrlen:传入传出。 &clit_addr_len

    入:addr的大小。 出:客户端addr实际大小。
    

    返回值

    成功:能与客户端进行数据通信的 socket 对应的文件描述。

    失败: -1 , errno

  • int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 使用现有的 socket 与服务器建立连接

    参数

    sockfd: socket 函数返回值

       struct sockaddr_in srv_addr;		// 服务器地址结构
    
       srv_addr.sin_family = AF_INET;
    
       srv_addr.sin_port = 9527 	跟服务器bind时设定的 port 完全一致。
    
       inet_pton(AF_INET, "服务器的IP地址",&srv_adrr.sin_addr.s_addr);
    

    addr:传入参数。服务器的地址结构

    addrlen:服务器的地址结构的大小

    返回值

    成功:0

    失败:-1 errno

    如果不使用bind绑定客户端地址结构, 采用"隐式绑定".

五、sockaddr地址结构

IP + port --> 在网络环境中唯一标识一个进程。

struct sockaddr_in addr;

	addr.sin_family = AF_INET/AF_INET6				man 7 ip

	addr.sin_port = htons(9527);
			
		int dst;

		inet_pton(AF_INET, "192.157.22.45", (void *)&dst);

	addr.sin_addr.s_addr = dst;

	【*】addr.sin_addr.s_addr = htonl(INADDR_ANY);		取出系统中有效的任意IP地址。二进制类型。

	bind(fd, (struct sockaddr *)&addr, size);