Linux程序设计-网络通信socket [总结概况版][复习专用][速通]

Linux程序设计系列-博客导航 [总结概况版][复习专用][速通][完结]_yasuo626的博客-CSDN博客

导航

当前章节:网络通信socket
原文链接:网络通信socket
上一章节:进程间通信IPC
目录:Linux程序设计

socket

介绍

套接字是网络通信的端点。它允许进程通过网络进行通信,交换字节流。
服务器端创建socket,通过bind转为被动,再通过accept接收连接的客户端
客户端建立socket后直接connect与服务器连接,连接成功后可以通过socket进行网络通信。

socket创建

int socket(int domain, int type, int protocol);
参数:
domain 地址族,IP 地址类型AF_INET/AF_INET6 表示ipv4和ipv6
type:SOCK_STREAM/SOCK_DGRAM 为字节流和数据包传输方式
protocol 默认0自动选择协议,IPPROTO_TCP流式TCP, IPPTOTO_UDP数据报UDP
返回
成功返回对应socketid,否则-1

addr数据结构

在进行连接过程中,需要指定连接服务器的ip和端口。
结构sockaddr是一个通用的套接字地址结构。它保存各种地址族的地址信息,并作为参数传递给bind()、connect()和sendto()等套接字函数。

<sys/socket.h>:
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
struct sockaddr_in {
short sin_family; // Address family, AF_INET
unsigned short sin_port; // Port number
struct in_addr sin_addr; // IPv4 address
char sin_zero[8]; // Padding
};
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
inet_pton(AF_INET, “127.0.0.1”, &addr.sin_addr);

字节序转换

计算机存储有大端存储和小端存储,大端存储低地址放数据的高位,小端存储相反,网络字节序指定大端存储,因此需要转换。
int inet_pton(int af, const char *src, void *dst); 将字符串ip转为网络字节序
inet_ntop(int af, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
INET_ADDRSTRLEN是一个宏,定义该缓冲区的最大大小(IPv4为16字节,IPv6为46字节)。
addr.sin_addr.s_addr = htonl(INADDR_ANY);
uint16_t htons(uint16_t hostshort); 将主机字节序的端口转为网络字节序。
ntohs(client_addr.sin_port); 将网络字节序的端口转为主机字节序。

bind绑定

int bind(int sockfd, const struct sockaddr addr, socklen_t addrlen);
bind(sockfd, (struct sockaddr
) &addr, sizeof(addr));
成功返回0 错误返回-1

  • 它用于将网络地址和端口号与套接字相关联。
  • 在流套接字可以接受传入连接或数据报套接字可以接收数据包之前,必须调用它。
  • addr指向指定地址和端口的sockaddr结构。INADDR_ANY可用于侦听所有接口。
  • 如果不同的地址族使用不同大小的sockaddr结构,则必须指定addrlen。
  • 套接字一旦绑定,就无法绑定到另一个地址。必须再次调用bind()才能更改绑定。
  • 在已连接或已绑定的套接字上调用bind()将失败,errno将设置为EINVAL。
  • 成功后,bind()返回0。出现错误时,将返回-1,并适当设置errno。
  • 1024以下的端口号是为系统服务保留的,除非程序具有根权限,否则无法绑定到。
  • 指定已在使用的地址将导致“地址已在使用”错误(EADDRINUSE)。一个地址/端口对只能绑定一个套接字。
  • Unix域套接字不需要调用bind(),它们可以直接使用connect()。但如果调用bind(),addr必须指向sockaddr_un结构。
  • 一旦绑定,套接字即使在创建它的进程终止后仍然存在,直到设置了SO_REUSEADDR选项,并且另一个套接字绑定到同一地址/端口对。
    bind()中的一些错误示例如下:
    -EINVAL-套接字已绑定到一个地址。
    -EADDRNOTAVAIL-指定的地址无法绑定。
    -EADDRINUSE-指定的地址已在使用中。
    -EACCESS-权限不足,无法绑定端口。

listen监听

将主动的socket转为被动,并设置最大监听数量
listen(listenfd, 10);

accept接受

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
传入server的socketfd并传入存放client地址的addr,以及长度。
返回与client连接的新的fd,为-1表示连接失败

connect连接

connect()系统调用将套接字连接到远程地址和端口。
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
客户端需要与服务器端口和ip一致,否则无法连接
连接成功返回0,连接传入的fd可以与服务器通信,否则-1

通信

  • send和recv直接通信
    ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    flag一般设置0
    发送成功返回发送直接数,否则-1
    接收成功返回接收字节数,0为对方关闭套接字,-1为接收失败

  • read() / write()
    直接使用文件读写方式,这种方式容易出现问题。

  • sendmsg/recvmsg
    ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
    ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
    它们的工作方式与send()和recv()类似,但允许在msghdr结构中传递额外的元数据和控制信息。

    struct msghdr {
    void *msg_name; // protocol address
    socklen_t msg_namelen; // size of protocol address
    struct iovec *msg_iov; // scatter/gather array
    int msg_iovlen; // elements in msg_iov
    void *msg_control; // ancillary data (cmsghdr struct)
    socklen_t msg_controllen; // length of ancillary data
    int msg_flags; // flags returned by recvmsg()
    };
    msghdr可以存放一个消息数组,消息数组里面可以有多个消息如下:
    struct iovec {
    void iov_base; / Starting address /
    size_t iov_len; / Number of bytes to transfer */
    };

  • UDP数据通信

    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
    const struct sockaddr *dest_addr, socklen_t addrlen);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

aidroid

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

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

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

打赏作者

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

抵扣说明:

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

余额充值