目录
前言:
在Linux下,实现传输层协议为TCP的套接字进行网络通信,网络层协议为IPv4,需要用到的接口如下:实现服务器的接口有(socket、bind、listen、accept、read、write),实现客户端的接口有(socket、connect、write、read)。
实现方式:因为网络通信的本质是进程间通信在云服务器上创建一个服务器进程和一个客户端进程,服务器进程先启动,然后让客户端链接到服务器上,至此客户端可以向服务器发送消息,并且服务器收到消息后可以给对方反馈信息。
TCP通信示意图如下:
1、实现服务器的逻辑
将服务器封装成一个类,服务器的端口号、IP地址以及网络描述符(一种类似文件描述符的字段)作为类的成员变量,这样做的好处是对软件实现分层,方便维护代码。按照下文的接口顺序调用实现服务器类。
1.1 socket
实现网络通信的第一步基本都是调用socket接口,目前已经明确传输层协议为TCP,网络层协议为IPv4,因此可以直接调用socket,该函数介绍如下:
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
//domain表示网络层协议,填AF_INET表示IPv4,填AF_INET6表示IPv6
//type表示传输层协议,SOCK_STREAM为TCP,SOCK_DGRAM为UDP
//protocol表示指定特定的协议,默认填0即可
//调用成功返回一个类型文件描述符的网络描述符,失败返回-1
1.2 bind
在网络通信中,bind函数与socket函数密不可分,他是用来绑定网络描述符和地址信息的,目的是让后续的通信可以直接通过网络描述符进行。在使用bind函数前,需要先创建一个包含地址信息的结构体,IPv4对应的结构体类型是struct sockaddr_in,该结构体里需要程序员手动填写3个信息,分别是:1、TCP/UDP,2、自定义的端口号,3、该主机的IP地址。
体现地址信息的伪代码如下:
struct sockaddr_in local;//定义变量
memset(&local, 0, sizeof(local));//对内部内容清零
local.sin_family = AF_INET;//填写ip协议
local.sin_port = htons(port_);//填写端口号
inet_aton(ip_.c_str(), &(local.sin_addr));//填写ip地址
其中由于网络传输数据规定以大端字节序传输,因此填写端口号和ip时需要对其进行大端字节序的转换,这里可以调用htons函数和inet_aton函数实现转换,这两个函数的介绍如下:
#include <arpa/inet.h>
uint16_t htons(uint16_t hostshort);
//将主机字节序转换成网络大端字节序,以返回值的形式转换
#include <arpa/inet.h>
int inet_aton(const char *string, struct in_addr*addr);
//将字符串形式的ip转换成网络字节序,并直接赋值给addr指向的空间
在地址信息完善后,紧接着就是调用bind函数进行绑定,bind函数介绍如下:
int bind(int socket, const struct sockaddr *address,
socklen_t address_len);
//socket表示要绑定的网络描述符
//address表示指向的地址信息变量
//address_len表示地址信息变量的大小
//调用成功返回0,失败返回-1并设置错误码
1.3 listen
与UDP不同的是,UDP绑定之后就可以用网络描述符进行接收和发送消息的操作了,但是TCP不一样,TCP的绑定完成后