网络编程之TCP通信

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 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值