TCP常见接口
创建套接字:(TCP/UDP)
int socket(int domain, int type, int protocol);
inet_aton,将字符串IP转换成整数IP
int inet_aton(const char *cp, struct in_addr *inp);
监听套接字:(TCP,服务器)
int listen(int sockfd, int backlog);
TCP服务器在与客户端进行网络通信之前,服务器需要先获取到客户端的连接请求,获取连接的函数叫做accept
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数说明:
- sockfd:特定的监听套接字,表示从该监听套接字中获取连接。
- addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。
- addrlen:调用时传入期望读取的addr结构体的长度,返回时代表实际读取到的addr结构体的长度,这是一个输入输出型参数
return val :
- 获取连接成功返回接收到的套接字的文件描述符,获取连接失败返回-1,同时错误码会被设置。
如何理解accept函数返回的套接字?
- 调用accept函数获取连接时,是从监听套接字当中获取的。如果accept函数获取连接成功,此时会返回接收到的套接字对应的文件描述符
监听套接字与accept函数返回的套接字
1、监听套接字:用于获取客户端发来的连接请求。accept函数会不断从监听套接字当中获取新连接。
2、accept函数返回的套接字:用于为本次accept获取到的连接提供服务。监听套接字的任务只是不断获取新连接,而真正为这些连接提供服务的套接字是accept函数返回的套接字,而不是监听套接字
telnet 是一个基于网络的命令行工具,用于远程登录到另一台计算机
inet_ntop,将整数IP转换成字符串IP
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
-
af:地址族,指定要转换的地址类型。常见的值有 AF_INET(IPv4)和 AF_INET6(IPv6)。
-
src:指向包含原始网络地址的缓冲区的指针。
-
dst:指向目标缓冲区的指针,该缓冲区将接收转换后的文本表示。如果 dst 为 NULL,则 inet_ntop 将分配一个足够大的缓冲区,并返回指向该缓冲区的指针。
-
size:目标缓冲区的大小
建立连接:(TCP,客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
inet_pton,将一个点分十进制的IP地址字符串转换为网络字节顺序的数值形式
int inet_pton(int af, const char *src, void *dst);
af:指定地址族,可以是 AF_INET(IPv4)或 AF_INET6(IPv6)。
src:指向一个以 null 结尾的字符串,包含要转换的IP地址。
dst:指向一个用于存储转换后的数值地址的缓冲区。
服务端
服务端创建套接字
TCP服务器创建套接字的做法与UDP服务器是一样的
服务端绑定
创建完套接字后我们还需要调用bind函数进行绑定操作
如何绑定
定义一个struct sockaddr_in结构体,将服务器网络相关的属性信息填充到该结构体当中,比如协议家族、IP地址、端口号等。
填充服务器网络相关的属性信息时,协议家族对应就是AF_INET,端口号就是当前TCP服务器程序的端口号。在设置端口号时,需要调用htons函数将端口号由主机序列转为网络序列。
在设置服务器的IP地址时,可以设置为本地环回127.0.0.1,表示本地通信。也可以设置为公网IP地址,表示网络通信。
如果使用的是云服务器,那么在设置服务器的IP地址时,不需要显示绑定IP地址,直接将IP地址设置为INADDR_ANY即可,此时服务器就可以从本地任何一张网卡当中读取数据。此外,由于INADDR_ANY本质就是0,因此在设置时不需要进行网络字节序的转换。
填充完服务器网络相关的属性信息后,需要调用bind函数进行绑定。绑定实际就是将文件与网络关联起来,如果绑定失败也没必要进行后续操作了,直接终止程序即可。
服务端监听
TCP服务器是面向连接的,客户端在正式向TCP服务器发送数据之前,需要先与TCP服务器建立连接,然后才能与服务器进行通信。
因此TCP服务器需要时刻注意是否有客户端发来连接请求,此时就需要将TCP服务器创建的套接字设置为监听状态
listen函数可以设置套接字为监听状态
服务端获取连接
TCP服务器在与客户端进行网络通信之前,服务器需要先获取到客户端的连接请求
accept是获取连接的函数
服务端处理请求
现在TCP服务器已经能够获取连接请求了,下面当然就是要对获取到的连接进行处理
为客户端提供服务的不是监听套接字,因为监听套接字获取到一个连接后会继续获取下一个请求连接,为对应客户端提供服务的套接字实际是accept函数返回的套接字
客户端
客户端创建套接字
客户端不需要进行绑定和监听:
服务端要进行绑定:
服务端的IP地址和端口号必须要众所周知,不能随意改变。客户端虽然也需要IP地址和端口号,tcp的客户端是需要bind端口号,但是不需要显示的bind端口号 ,由操作系统随机选择端口号
服务端需要进行监听
服务端需要通过监听来获取新连接,但是不会有人主动连接客户端,因此客户端是不需要进行监听操作的
客户端必须要知道它要连接的服务端的IP地址和端口号,因此客户端除了要有自己的套接字之外,还需要知道服务端的IP地址和端口号,这样客户端才能够通过套接字向指定服务器进行通信
客户端连接服务器并发起请求
当客户端创建完套接字后就可以向服务端发起连接请求。
调用connect函数向服务端发起连接请求时
代码
单进程版本
多进程版本
多进程版本关于sockfd
线程版本