C++ Linux多进程Socket通信

原文链接:C++ Linux多进程Socket通信

接口函数

套接字由于本身是为计算机网络服务的,因此相比于一般的通信方式,套接字会更复杂.

socket创建与连接

// 创建套接字
int socket(int domain, int type, int protocol);
    return fd ID(成功) -1(错误)
    domain协议族 AF_INET(IPV4) AF_INET6(IPV6) AF_UNIX AF_LOCAL 用于本机通信
    type类型 SOCK_STREAM(TCP) SOCK_DGRAM(UDP) SOCK_RAW(原始套接字)
    protocol协议  0为自动选择 有IPPROTO_TCP和IPPROTO_UDP

// 绑定计算机实际的端口
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    return 0(成功) -1(错误)
    sockfd: socket返回的文件描述符
    addr: IP的地址结构体(下面详细介绍)
    addrlen: 由于不同的协议地址长度不同,需要指定

// 监听
int listen(int sockfd, int backlog);
    return 0(成功) -1(错误)
    backlog为最大连接数

// 客户端请求连接(仅针对有连接服务)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    return 0(成功) -1(错误)
    sockfd: 客户端的socket
    addr,addrlen:服务器IP和大小
    
// 接受连接(服务器接收客户端连接)
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
    return 与客户端通信的fd(成功) -1(错误)
    sock: 服务器的socket
    addr,addrlen:请求连接的客户端IP和大小

地址创建与转换

套接字的IP和端口需要进行处理后才能传入

由于计算机本身字节序和网络字节序不一定一致,需要进行处理转换,都是大端不需要转,而小端字节序需要和网络字节序相互转换.

IP:PORT 以IPV4为例 每个数字1字节0-255,4个字段需要32位为无符号int,端口0-65535 16位2字节,都按照网络字节序存放.

V6由于地址更长有128位,因此结构与v4不同,并且有些服务可能没有考虑到v6用户的支持,某些服务v6会存在问题.

#include <arpa/inet.h>

IPV4的地址结构体:
struct sockaddr_in {
   
    short int          sin_family;  // 地址族,通常为 AF_INET 或v6
    unsigned short int sin_port;    // 端口号,网络字节序
    struct in_addr     sin_addr;    // IP 地址
};
// `struct in_addr` 定义如下:
struct in_addr {
   
    uint32_t s_addr;  // IP 地址,网络字节序,32位无符号,4字节,每个字节0-255
};

//IPV4字符串转32位网络字节序IP
in_addr_t inet_addr(const char *cp);
   return 网络字节序地址(成功) INADDR_NONE(错误)






V6由于地址更长有128,因此结构与v4不同
struct sockaddr_in6
// 端口转换 
//主机转网络 host to network short
uint16_t htons(uint16_t hostshort); 
   return 大端序端口号(成功)
// 网络转主机
uint16_t ntohs(uint16_t netshort);
   return 主机端口号(成功)


// 地址转换(包括IP)
// 主机 转 网络
int inet_pton(int af, const char *src, void *dst);
    return 成功则为1,若输入不是有效的表达式则为0,若出错则为-1

// 网络 转 主机
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
    return 字符指针(成功) NULL(错误)
    af: 协议族AF_INET 或AF_INET6
    src,dst: 原IP字符串和目的字符串
    size: IP长度大小

通信接口

连接建立后可以相互发送数据,socket提供3种通信方法

注意一点,由于socket网络建立连接后本质还是通过IO读写的,可以通过fcntl控制阻塞和非阻塞特性

  1. 传统文件描述符通信:和读写文件一样流式读写
ssize_t write(int fd, const void *buf, size_t nbytes);
    return n(字节数) -1(错误)
ssize_t read(int fd, void *buf, size_t nbytes);
    return n(字节数) -1(错误)
  1. 更安全高效的接口通信:linux提供了结构体形式发生消息,更高效稳定安全

send和recv相比文件读写,可以参数控制并且会受协议影响实际工作方式
ssize_t send(int sockfd, const void buf[.len], size_t len, int flags);
    return n(字节数) -1(错误)
ssize_t recv(int sockfd, void buf[.len], size_t len,int flags);
    return n(字节数) -1(错误)


支持更复杂的消息处理和附加控制信息
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
    return n(字节数) -1(错误)
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
    return n(字节数) -1(错误)

flags 标志:
    0:默认标志,表示普通的数据发送操作。
    MSG_OOB:发送带外数据,通常用于紧急数据。
    MSG_DONTROUTE:绕过路由表,直接发送数据到目标主机。
    MSG_NOSIGNAL:不产生信号(在某些系统中),用于避免在发送数据时中断进程。



其中消息结构体为:
struct msghdr {
   
    void         *msg_name;       /* 地址 */
    socklen_t     msg_namelen;    /* 地址长度 */
    struct iovec *msg_iov;        /* 指向 iovec 结构体的指针 */
    size_t        msg_iovlen;     /* iovec 结构体的数量 */
    void         *msg_control;    /* 指向控制信息的指针 */
    size_t        msg_controllen; /* 控制信息的长度 */
    int           msg_flags;      /* 消息标志 */
};
数据指针结构:
struct iovec {
   
    void  *iov_base;  /* 数据缓冲区的起始地址 */
    size_t iov_len;   /* 数据缓冲区的长度 */
};

  1. 面向无连接的UDP通信:使用下面两个接口
ssize_t sendto(int sockfd, const void buf[.len], size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void buf[restrict .len], size_t len,int flags,struct sockaddr *_Nullable restrict src_addr,socklen_t *_Nullable restrict addrlen);

UDP存在数据丢失可能,但是客户端加入多播组,可以实现多播,适合视频流等

实例

使用tcp send/recv阻塞通信

服务器监听,客户端连接,之后相互发送一个消息

server


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aidroid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值