Linux软件编程学习笔记(十)——网络(二)——TCP通信

一、TCP简介

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接、可靠的字节流传输协议

TCP在通信前需要进行三次握手 建立连接,通信过程中具有数据确认机制,通信结束时通过四次挥手断开连接。TCP还通过滑动窗口、拥塞控制、掉线检测等机制保证通信的可靠性。

与UDP相比:

TCP UDP
面向连接 无连接
可靠传输 不可靠传输
通信前需要建立连接 不需要建立连接
资源占用较多 资源占用较少
适合文件传输、聊天等 适合实时性要求较高的场景

二、TCP通信流程

TCP通信分为客户端服务器端

1. TCP客户端

基本流程:

复制代码
socket()
   ↓
connect()
   ↓
send()/recv()
   ↓
close()

2. TCP服务器

基本流程:

复制代码
socket()
   ↓
bind()
   ↓
listen()
   ↓
accept()
   ↓
send()/recv()
   ↓
close()

因此,TCP最重要的函数就是:

复制代码
socket
bind
listen
accept
connect
send
recv

文档中也是按照这个流程介绍TCP通信接口的。


三、socket()

复制代码
int socket(int domain, int type, int protocol);

作用:

创建一个用于网络通信的套接字。

TCP通常使用:

复制代码
int sockfd = socket(AF_INET, SOCK_STREAM, 0);

其中:

复制代码
AF_INET

表示使用IPv4。

复制代码
SOCK_STREAM

表示使用流式套接字,也就是TCP。

返回值:

复制代码
成功:返回新的文件描述符
失败:返回-1

四、connect()

复制代码
int connect(int sockfd,
            const struct sockaddr *addr,
            socklen_t addrlen);

作用:

客户端向服务器发起连接。

例如:

复制代码
ret = connect(sockfd,
              (struct sockaddr *)&recvaddr,
              sizeof(recvaddr));

参数:

  • sockfd:套接字文件描述符

  • addr:服务器地址

  • addrlen:地址长度

返回值:

复制代码
成功:0
失败:-1

五、bind()

复制代码
int bind(int sockfd,
         const struct sockaddr *addr,
         socklen_t addrlen);

作用:

将IP地址和端口号绑定到套接字。

例如:

复制代码
bind(sockfd,
     (struct sockaddr *)&recvaddr,
     sizeof(recvaddr));

服务器必须先通过 bind() 指定自己的IP地址和端口。

注意:

bind()只能绑定本机的IP地址,不能绑定其他主机的IP地址;一个端口被占用后,也不能重复绑定。


六、listen()

复制代码
int listen(int sockfd, int backlog);

作用:

让服务器进入监听状态,等待客户端连接。

例如:

复制代码
ret = listen(sockfd, 10);

其中:

复制代码
sockfd

是监听套接字。

复制代码
backlog

表示等待处理的连接请求数量。

成功返回 0,失败返回 -1


七、accept()

复制代码
int accept(int sockfd,
           struct sockaddr *addr,
           socklen_t *addrlen);

作用:

从监听队列中取出一个客户端连接。

例如:

复制代码
confd = accept(sockfd, NULL, NULL);

这里要特别注意:

复制代码
sockfd

复制代码
confd

作用不同。

sockfd

负责:

复制代码
socket
bind
listen
accept

主要用于监听客户端连接

confd

accept()成功以后返回的新的文件描述符。

负责:

复制代码
send
recv

也就是真正和客户端进行数据通信

复制代码
              服务器

          sockfd
             │
           listen
             │
           accept
             ↓
           confd
          ↙     ↘
       send     recv

accept()成功后会返回新的文件描述符用于通信。


八、send()

复制代码
ssize_t send(int sockfd,
             const void *buf,
             size_t len,
             int flags);

作用:

向TCP套接字发送数据。

例如:

复制代码
char buf[1024] = "hello";

send(sockfd, buf, strlen(buf), 0);

参数:

  • sockfd:套接字文件描述符

  • buf:发送数据的首地址

  • len:发送数据长度

  • flags:属性,一般使用 0

返回值:

复制代码
成功:实际发送的字节数
失败:-1

九、recv()

复制代码
ssize_t recv(int sockfd,
             void *buf,
             size_t len,
             int flags);

作用:

从TCP套接字中接收数据。

例如:

复制代码
nret = recv(sockfd, buf, sizeof(buf), 0);

返回值:

复制代码
>0    成功接收到的字节数
-1    接收失败
0     对方关闭连接

这一点非常重要:

复制代码
if (nret == 0)
{
    printf("对方已经断开连接\n");
}

文档中也特别指出:如果对方关闭连接,recv()返回0。


十、TCP服务器和客户端总结

客户端

复制代码
socket();

connect();

send();
recv();

close();

可以记成:

复制代码
创建 → 连接 → 通信 → 关闭

服务器

复制代码
socket();

bind();

listen();

accept();

send();
recv();

close();

可以记成:

复制代码
创建 → 绑定 → 监听 → 接收连接 → 通信 → 关闭

十一、TCP文件传输

TCP不仅可以传输字符串,也可以传输文件。

基本思路:

客户端

复制代码
打开文件
   ↓
read()
   ↓
send()
   ↓
read()
   ↓
send()
   ↓
文件发送完成

服务器

复制代码
创建文件
   ↓
recv()
   ↓
write()
   ↓
recv()
   ↓
write()
   ↓
文件接收完成

例如:

复制代码
while (1)
{
    nret = read(fd, tmpbuff, sizeof(tmpbuff));

    if (nret <= 0)
    {
        break;
    }

    send(sockfd, tmpbuff, nret, 0);
}

服务器:

复制代码
while (1)
{
    nret = recv(confd, tmpbuff, sizeof(tmpbuff), 0);

    if (nret == 0)
    {
        break;
    }

    write(fd, tmpbuff, nret);
}

这里也能看到TCP和普通文件IO之间的联系:Socket本质上也是一种文件描述符 ,可以通过 send()recv()进行网络数据读写。


十二、TCP三次握手

TCP建立连接之前需要进行三次握手:

复制代码
客户端                         服务器

   SYN  -------------------->

        <-------------------  SYN + ACK

   ACK  -------------------->

          连接建立

目的主要是:

  1. 确认双方具有正常的发送和接收能力

  2. 建立TCP连接

  3. 同步双方的序列号

TCP通信前需要三次握手建立连接,这是TCP区别于UDP的重要特点之一。


十三、TCP四次挥手

通信结束时需要断开TCP连接:

复制代码
客户端                         服务器

   FIN  -------------------->

        <-------------------  ACK

        <-------------------  FIN

   ACK  -------------------->

          连接关闭

TCP通过四次挥手完成连接关闭。


相关推荐
CoderYanger1 小时前
A.每日一题:835. 图像重叠
java·开发语言·程序人生·leetcode·面试·职场和发展·学习方法
QYRdata2 小时前
年均增速24.2%!机器人数据湖未来六年增长动能强劲
网络·机器人·服务发现
CHENKONG_CK2 小时前
破解制鞋打磨痛点:RFID赋能去毛刺工序自动化升级
网络·单片机·嵌入式硬件·网络协议·tcp/ip
伞伞悦读2 小时前
【第37期】Python JSON 与配置详解:序列化、反序列化、嵌套结构和配置文件
开发语言·python·json
chshang19922 小时前
工业路由器是什么?浅谈5G工业网络中的IR602
网络·物联网·5g·智能路由器
CCCCCCCCharlie2 小时前
Linux进程控制四大核心操作
linux·开发语言
萧瑟余晖3 小时前
Netty 核心组件与 Reactor 模型详解
网络·架构
Brilliantwxx3 小时前
【STM32】 SPI Flash 驱动开发实战:阻塞模式驱动 W25Q64(含工程代码)
开发语言·stm32·单片机·嵌入式硬件
ITxiaobing20233 小时前
IP 定位服务选型指南:从准确率到工程落地的技术考察
linux·服务器·网络
wuyk5553 小时前
【Socket 进阶之路】第 9 章 Linux 网络服务量产稳定性优化|心跳保活、TIME_WAIT、SO_LINGER、内存池、断线重连、完整异常防护框架
linux·服务器·开发语言·网络·物联网