tcp简单通信程序详解
本篇博客的目的是用socket套接字及接口实现一个简单的tcp聊天程序。
实现步骤
服务端:
- 创建套接字listen_sock
- 绑定地址信息(IP地址,端口号)
- 监听套接字listen_sock
- 与服务端建立链接
- 接收客户端发来的数据
- 向客户端发送数据
- 关闭套接字
客户端:
8. 创建套接字sockfd
9. 绑定地址信息(内部完成,不手动绑定)
10. 申请与客户端建立连接
11. 建立连接成功
12. 向服务端发送数据
13. 接收服务端发来的数据
14. 关闭套接字
服务端:
1.创建套接字socket
//1.创建监听套接字listen_sock,参数依次为版本IPv4,流式套接字,默认tcp
int listen_sock = socket(AF_INET,SOCK_STREAM,0);
if (listen_sock < 0)
{
perror("create socket failed!");
return -1;
}
2.绑定地址信息
//2.为服务器绑定地址信息,以后凡是向服务器发起连接请求,都会首先让listen_sock处理。
struct sockaddr_in server_addr; //sockaddr_in仅用于IPv4
socklen_t size = sizeof(server_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[2]));//先将命令行第二个参数(端口号)转为整形再转为网络字节序。
server_addr.sin_addr.s_addr = inet_addr(argv[1]);//将命令行第一个参数(ip地址)转为网络字节序。
int ret = bind(listen_sock,(struct sockaddr*)&server_addr,size);
这里创建一个地址信息块,存储了服务端的IP地址和端口号,在后面的bind函数中传入作为第二个参数,bind成功,就等同于向操作系统说明,只要是向这个IP地址和端口发送的数据,都先经过我listen_sock这里。
这里同时也要注意网络字节序的转换,我们先来看一看sockaddr_in的结构:
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
};
可以看出,port是无符号16位的整型,sin_addr则是4个字节的整型,
而在网络字节序的函数,我们应该选择的就是htons(host to net small )和inet_addr。
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);(对无符号long4个字节转换为网络字节序的顺序)
uint16_t htons(uint16_t hostshort);(对无符号short2个字节转换为网络字节序的数据)
uint32_t ntohl(uint32_t netlong);(将4个字节的网络字节序数据转换为当前的主机字节序数据)
uint16_t ntohs(uint16_t netshort);将一个16位(2个字节)由网络字节序转变为主机字节序
in_addr_t inet_addr(cons