C编程:socket网络编程
头文件
<arpa/inet.h>
大小端转换
网络大小端转换:htons
和 htons
表示从本地的小端模式(主机字节序)转到服务器的大端模式(网络字节序)。分别是对应16位的short和32位的long。
如果是从网络字节序转到主机字节序,则是 ntohs
、ntohl
IP地址的大小端转换
- 将字符串的IP地址进行大小端转换:
- 本机到服务端:
inet_pton(int 地址族 , const char* 要转换的点分十进制IP地址, void * 转换成功后大端整数IP的写入地址)
- 地址族:
AF_INET
为ipv4、AF_INET6
为ipv6 - 返回值:1表示成功,失败为0或者-1
- 地址族:
- 大端到小端:
inet_ntop(int 地址族, const void* 大端IP整数地址, char *得到的小端地址, socklen_t 第三个参数对应的内存字节数)
- 参数同上
- 返回值:成功就返回第三个参数的地址,通过返回值取出转哈un的IP,失败NULL
- 只能处理ipv4的一组函数:
- 小转大:
int_addr_t inet_addr(const char *cp)
- 大转小:
char* inet_ntoa(struct in_addr in);
- 小转大:
- 本机到服务端:
可以看出,小端的是字符串,大端的是整数型。
socket数据结构
//第一种,sockaddr
struct sockaddr{
sa_family_t sa_family; //地址族协议
char sa_data[14]; //2字节端口,4字节IP,8字节不管
};
//第二种,sockaddr_in
//两种字节数相同,推荐用后者。
struct sockaddr_in{
sa_family_t sin_family; // 地址族协议,AF_INET
in_port_t sin_port; //端口,2字节,大端
struct in_addr sin_addr; // IP地址,4字节,大端
//填充的八个字节,这里不写出来了。
}
socket函数
创建套接字
int socket(int 地址族协议, int 传输协议, int 协议)
- 第一个参数:AF_INE或者AF_INET6
- 第二个参数:
- SOCK_STREAM 流式传输
- SOCK_DGRAM 报文传输
- 第三个参数:一般写0,默认如果流式使用TCP,报式使用UDP
- 返回值:
- 成功:返回套接字文件描述符,指向内核中的某一块内存,网络通信基于这个文件描述符。
- 失败:-1
绑定IP和端口
int bind(int socket文件描述符fd, const struct sockaddr *addr, socklen_t addlen)
- 第一个参数:上面函数返回的文件描述符。
- 第二个参数:IP和端口封装的结构体,一般用sockaddr_in 强转为sockaddr 代替。
- 第三个参数:sizeof addr
- 返回值
- 成功0,失败-1
监听
int listen(int socket文件描述符fd, int backlog)
- 第二个参数为最大连接要求,最大值是128.
- 返回值:成功0,失败-1
阻塞并接收客户端的连接请求,建立新连接,得到通信的文件描述符
int accept(int 监听的文件描述符, struct sockaddr* addr , socklen_t * addrlen)
- 第一个参数:监听的文件描述符
- 第二个参数,存储建立连接的服务端的地址信息
- 第三个参数:存储addr指向的内存大小。
- 返回值:成功返回一个文件描述符,用于和这个客户端建立通信,调用失败返回-1
- 这个函数是一个阻塞函数,没有新的客户端请求的时候会阻塞。
接收数据
ssize_t read(int 通信文件描述符, void *buf 用于存储接受数据的有效内存, size_t size 内存容量)
ssize_t recv(int 通信文件描述符, void *buf 用于存储接受数据的有效内存, size_t size 内存容量, int flags)
- 第一个是accept 返回的文件描述符
- 第四个参数,一般不使用,指定为0
- 返回值
>0
为实际接受的字节数- =0 对方断开连接
- -1 接收数据失败
- 如果连接没有断开,会阻塞直到数据到达。当发送方断开连接不会阻塞,直接返回0.
发送数据
ssize_t write(int 通信文件描述符, const void* buf 要发送的字符串, size_t len )
ssize_t send(int 通信文件描述符, const void* buf 要发送的字符串, size_t len,int flags )
- 返回值
>0
为实际发送的字节- -1 表示数据发送失败
connect
- 成功连接服务器后,客户端这边会随机绑定一个IP和端口。
- 服务器调用的accept 就是存储客户端的IP和端口信息
int connect(int 通信文件描述符, const struct sockaddr *addr, socklen_t addrlen)
- 第一个参数,通信的文件描述符。
- 第二个参数,连接的服务端的地址信息,需要先转换为大端
- 第三个参数,addr指向的内存的大小。
- 返回值
- 成功0,失败-1
TCP通信流程
服务端
- 创建监听套接字,即调用socket函数。
- 将得到的文件描述符和本地端口绑定。
- 开始监听
- 等待客户端发送请求,连接成功后得到一个通信的文件描述符,没有新连接请求就阻塞。
- 通信,读写操作也是阻塞的。
- 关闭套接字,有两个。(监听的文字描述符只需要一个,负责监测客户端的请求,不负责通信;通信的文件描述符,如果有N个客户端进行通信就有N个)
服务端实现代码
客户端实现代码
- 感谢你赐予我前进的力量
赞赏者名单
因为你们的支持让我意识到写文章的价值🙏
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 AjaxZhan
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果