1 TCP通信协议模型
C/S模型

1.1TCP服务端创建流程
1)创建套接字(**socket( )**函数)
2)创建服务器的信息结构体并初始化(以通用的IPV4为例 struct sockaddr)
3)套接字绑定服务器信息结构体(**bind()**函数)
4)将套接字设置为监听状态(**listen( )**函数)
5)阻塞等待客户端的连接(**accept( )**函数)
6)服务端与客户端数据的收发
7)关闭与客户端通信的套接字
1.2TCP客户端创建流程
1)创建套接字(**socket( )**函数)
2)创建服务器的信息结构体并初始化(以通用的IPV4为例 struct sockaddr)
3)客户端连接服务器(**connect( )**函数)
4)服务端与客户端数据的收发
5)关闭与客户端通信的套接字
2 TCP通信所使用的API
2.1 socket函数
socket函数是一个创建套接字的系统调用,其原型如下:
#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并设置errno。
常用的几种协议族类型及其意义:
- AF_INET:IPv4协议族。
- AF_INET6:IPv6协议族。
- AF_UNIX:UNIX域协议族,用于同一台机器上的进程通信。
常用的几种套接字类型及其意义:
- SOCK_STREAM:面向连接的套接字,即TCP套接字。
- SOCK_DGRAM:无连接的套接字,即UDP套接字。
常用的几个传输协议及其意义:
- IPPROTO_TCP:TCP传输协议。
- IPPROTO_UDP:UDP传输协议。
socket函数成功后将返回一个套接字描述符。套接字描述符可以看作是内核中的一个数据结构,它包含了一些网络传输所需的参数信息,例如IP地址、协议、端口等。程序可以通过该描述符对此套接字进行操作,如读写数据、关闭套接字等。
如果套接字描述符为负数,则表示创建套接字失败。此时,可以根据errno变量查看错误码,确定失败的原因。例如:
- EAFNOSUPPORT:指定的协议族不支持。
- EPROTONOSUPPORT:指定的传输协议不支持。
- EMFILE:已达到进程打开文件的最大数量限制。
- EPERM:没有足够的权限创建套接字等。
总之,socket函数是网络编程中非常重要的一个函数,可用于创建套接字,并指定其传输类型及传输协议类型,是建立网络连接的基础。
2.2 bind函数
bind函数是用于将套接字与指定的IP地址和端口号进行绑定,使其能够在网络上唯一识别,其原型如下:
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- sockfd:要绑定的套接字描述符。
- addr:一个指向
sockaddr结构体的指针,包含了要绑定的IP地址和端口号信息。 - addrlen:addr指向的结构体的大小。
返回值:
- 成功时,返回0;
- 失败时,返回-1,并设置errno变量来指示错误的类型。
struct sockaddr可以根据不同的协议族类型进行定义。例如,在IPv4协议族中,使用struct sockaddr_in结构体表示套接字地址信息:
struct sockaddr_in {
sa_family_t sin_family; // 协议族类型,AF_INET
in_port_t sin_port; // 端口号
struct in_addr sin_addr; // IP地址
char sin_zero[8]; // 不使用
};
常用的几个字段及其意义:
- sin_family:协议族类型,应该设为
AF_INET。 - sin_port:端口号,需要转换为网络字节序后进行绑定。
- sin_addr:IP地址,需要转换为网络字节序后进行绑定。
在使用bind函数前,通常需要对IP地址和端口号进行初始化。例如:
#include <arpa/inet.h> // inet_addr函数和htons函数的头文件
struct sockaddr_in addr;
const char *ip = "127.0.0.1"; // IP地址
int port = 8080; // 端口号
memset(&addr, 0, sizeof(addr)); // 将结构体数据清零
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip); // 将IP地址字符串转换为in_addr_t类型的整数,并转换为网络字节序
addr.sin_port = htons(port); // 将主机字节序的端口号转换为网络字节序
在初始化完成后,即可使用bind函数将套接字描述符与指定的IP地址和端口号绑定。例如:
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建一个TCP套接字
if (sockfd < 0) {
perror("socket error");
exit(-1);
}
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind error");
exit(-1);
}
如果bind函数执行成功,则返回值为0;否则返回-1,并设置errno变量以表明错误的类型。常见的错误码包括:
- EACCES:没有足够的权限进行绑定。
- EADDRINUSE:指定的IP地址和端口已经被占用。
- EINVAL:不正确的套接字描述符或者指定的端口号范围不合法等。
总之,通过bind函数可以为套接字绑定一个唯一的网络地址,使其能够在网络上被唯一识别,并进行后续的数据传输。
2.3 listen函数
listen函数是用于将一个套接字转换为被动套接字,即用于监听连接请求的套接字,其原型如下:
#include <sys/socket.h>
int


2607

被折叠的 条评论
为什么被折叠?



