TCP网络编程概述、相关函数、及实现超详解

文章目录

  • TCP网络编程概述
    • 1. TCP协议的特点
    • 2. TCP与UDP的差异
    • 3. TCP编程流程
  • TCP网络编程相关函数详解
    • 1. `socket()`:创建套接字
      • 参数说明:
      • 返回值:
      • 示例:
    • 2. `connect()`:客户端连接服务器
      • 参数说明:
      • 返回值:
      • 示例:
    • 3. `bind()`:服务器绑定地址和端口
      • 参数说明:
      • 返回值:
      • 示例:
    • 4. `listen()`:监听连接请求
      • 参数说明:
      • 返回值:
      • 示例:
    • 5. `accept()`:接受客户端连接
      • 参数说明:
      • 返回值:
      • 示例:
    • 6. `send()`:发送数据
      • 参数说明:
      • 返回值:
      • 示例:
    • 7. `recv()`:接收数据
      • 参数说明:
      • 返回值:
      • 示例:
    • 8. `close()`:关闭连接
      • 参数说明:
      • 返回值:
      • 示例:
  • TCP客户端与服务端的实现案例
    • TCP客户端实现
    • TCP服务器实现


TCP网络编程概述

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的传输层协议,广泛应用于网络通信。与UDP(User Datagram Protocol,用户数据报协议)不同,TCP提供了可靠的数据传输机制,确保数据能够完整、有序地从发送端传输到接收端。本文将详细介绍TCP协议的特点、TCP与UDP的差异、TCP编程流程以及客户端和服务器的实现方式。

1. TCP协议的特点

TCP具有以下主要特点:

  1. 面向连接:在通信前,TCP必须先建立连接。
  2. 有序号和确认机制:每个数据包都带有序号,接收方需要发送确认序号,确保数据有序接收。
  3. 排序、检错和失败重传:TCP对接收到的数据进行排序,检查数据的完整性,如有错误,会进行重传。
  4. 大文件传输:由于TCP能够分片并重新组装数据包,它特别适合大文件的可靠传输。
  5. 不支持广播和多播:与UDP不同,TCP不支持广播和多播,只支持点对点通信。

在TCP通信中,客户端和服务器的角色各不相同:

  • TCP客户端:主动向服务器发起连接。
  • TCP服务器:被动等待客户端连接。

2. TCP与UDP的差异

特点TCPUDP
面向连接
可靠传输
顺序保证
传输效率较低(需要连接、确认等)较高(无连接、无确认)
数据传输大小限制有(单个数据包有限制)
广播/多播支持

TCP更适合需要可靠传输的应用场景,如文件传输、邮件等,而UDP更适合实时性要求高的应用,如视频、语音传输。

3. TCP编程流程

编写TCP程序时,主要流程如下:

  1. 创建套接字:使用socket()函数创建TCP套接字。
  2. 连接服务器(客户端)或绑定端口监听连接(服务器)。
  3. 发送或接收数据:通过send()recv()函数进行数据交换。
  4. 关闭连接:使用close()函数关闭套接字。
    在这里插入图片描述

TCP网络编程相关函数详解

在编写TCP程序时,通常会使用一系列网络函数来创建套接字、建立连接、发送/接收数据并关闭连接。下面将对TCP网络编程中常用的函数进行详细讲解,以帮助读者更好地理解每个函数的用途及其使用方法。

1. socket():创建套接字

socket()函数是网络编程的基础,用于创建套接字(Socket)。套接字是网络通信的端点,类似于两台设备之间的通信通道。它的定义如下:

int socket(int domain, int type, int protocol);

参数说明:

  • domain:指定通信使用的地址族,常用的有:
    • AF_INET:IPv4网络协议。
    • AF_INET6:IPv6网络协议。
  • type:指定套接字类型,常用的有:
    • SOCK_STREAM:流式套接字,用于TCP连接。
    • SOCK_DGRAM:数据报套接字,用于UDP连接。
  • protocol:一般为0,表示使用默认协议(TCP或UDP)。

返回值:

  • 成功:返回套接字的文件描述符。
  • 失败:返回-1,并设置errno

示例:

int sock = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字
if (sock < 0) {perror("socket creation failed");
}

2. connect():客户端连接服务器

connect()函数用于客户端主动向服务器发起连接请求。在TCP连接中,客户端通过该函数连接指定的服务器。

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数说明:

  • sockfd:客户端套接字描述符。
  • addr:服务器的地址结构,通常为struct sockaddr_in
  • addrlen:地址结构的大小。

返回值:

  • 成功:返回0。
  • 失败:返回-1,并设置errno

示例:

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8000); // 服务器端口号
server_addr.sin_addr.s_addr = inet_addr("10.35.184.221"); // 服务器IP地址if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {perror("connect failed");
}

3. bind():服务器绑定地址和端口

bind()函数用于将套接字绑定到指定的IP地址和端口号。服务器需要通过bind()来指定其服务的地址和端口。

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数说明:

  • sockfd:服务器套接字描述符。
  • addr:服务器地址结构,通常为struct sockaddr_in
  • addrlen:地址结构的大小。

返回值:

  • 成功:返回0。
  • 失败:返回-1,并设置errno

示例:

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(9000); // 绑定端口9000
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定本机所有IPif (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {perror("bind failed");
}

4. listen():监听连接请求

服务器通过listen()函数来监听客户端的连接请求,进入监听状态,准备接受客户端的连接。

int listen(int sockfd, int backlog);

参数说明:

  • sockfd:服务器套接字描述符。
  • backlog:连接队列的大小,表示服务器可以处理的等待连接的客户端数量。

返回值:

  • 成功:返回0。
  • 失败:返回-1,并设置errno

示例:

if (listen(sock, 5) != 0) { // 最大连接等待队列长度为5perror("listen failed");
}

5. accept():接受客户端连接

accept()函数用于服务器从连接队列中取出一个客户端连接,生成一个新的套接字,用于和该客户端进行通信。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数说明:

  • sockfd:服务器监听套接字。
  • addr:客户端地址结构,用于存储连接的客户端信息。
  • addrlen:地址结构的大小。

返回值:

  • 成功:返回一个新的已连接套接字描述符,用于与客户端通信。
  • 失败:返回-1,并设置errno

示例:

struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_sock = accept(sock, (struct sockaddr *)&client_addr, &client_len);
if (client_sock < 0) {perror("accept failed");
}

6. send():发送数据

send()函数用于向指定的套接字发送数据。

ssize_t send(int sockfd, const void *buffer, size_t length, int flags);

参数说明:

  • sockfd:套接字描述符。
  • buffer:指向需要发送数据的缓冲区。
  • length:要发送的数据长度。
  • flags:通常为0,可选其他标志位。

返回值:

  • 成功:返回发送的字节数。
  • 失败:返回-1,并设置errno

示例:

char message[] = "Hello, TCP Server!";
if (send(sock, message, strlen(message), 0) < 0) {perror("send failed");
}

7. recv():接收数据

recv()函数用于从指定的套接字接收数据。

ssize_t recv(int sockfd, void *buffer, size_t length, int flags);

参数说明:

  • sockfd:套接字描述符。
  • buffer:指向接收数据的缓冲区。
  • length:缓冲区大小。
  • flags:通常为0,可选其他标志位。

返回值:

  • 成功:返回接收到的字节数。
  • 失败:返回-1,并设置errno
  • 如果连接被关闭,返回0。

示例:

char buffer[128];
ssize_t bytes_received = recv(sock, buffer, sizeof(buffer), 0);
if (bytes_received > 0) {buffer[bytes_received] = '\0'; // 确保数据是以字符串形式输出printf("Received data: %s\n", buffer);
} else if (bytes_received == 0) {printf("Connection closed by peer\n");
} else {perror("recv failed");
}

8. close():关闭连接

close()函数用于关闭指定的套接字,释放相关资源。

int close(int sockfd);

参数说明:

  • sockfd:需要关闭的套接字描述符。

返回值:

  • 成功:返回0。
  • 失败:返回-1,并设置errno

示例:

close(sock); // 关闭套接字

TCP客户端与服务端的实现案例

TCP客户端实现

在TCP客户端编程中,客户端主动发起与服务器的连接。以下是一个基本的TCP客户端代码示例:

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>typedef struct sockaddr_in addr_in;
typedef struct sockaddr addr;int main(int argc, char const *argv[]) {// 创建TCP套接字int sock = socket(AF_INET, SOCK_STREAM, 0);// 连接TCP服务器addr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8000);server_addr.sin_addr.s_addr = inet_addr("10.35.184.221");if (connect(sock, (addr *)&server_addr, sizeof(server_addr)) != 0) {perror("connect");return -1;}printf("TCP server connect OK\n");// 每2秒发送一次数据int n = 0;while (1) {char data[] = "hi, tcp server!";if (send(sock, data, strlen(data), 0) > 0) {printf("(%d)发送成功!\n", ++n);}sleep(2);}close(sock);return 0;
}

TCP服务器实现

TCP服务器是被动的,等待客户端连接。在实现中,服务器需要首先绑定地址并监听客户端连接,接着通过accept()函数接受客户端的连接。以下是一个简单的单聊TCP服务器实现:

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>typedef struct sockaddr_in addr_in;
typedef struct sockaddr addr;typedef struct {int sock;char ip[INET_ADDRSTRLEN];
} client_info;void *readTask(void *arg) {client_info *info = (client_info *)arg;while (1) {char buf[128] = "";ssize_t len = recv(info->sock, buf, 128, 0);if (len > 0) {printf("%s: %s\n", info->ip, buf);}}
}void *sendTask(void *arg) {client_info *info = (client_info *)arg;while (1) {char buf[128] = "";fgets(buf, 128, stdin);buf[strlen(buf)-1] = 0;send(info->sock, buf, strlen(buf), 0);if (strncmp(buf, "bye", 3) == 0) break;}
}int main(int argc, char const *argv[]) {if (argc != 2) return -1;// 创建TCP套接字int sock = socket(AF_INET, SOCK_STREAM, 0);// 设置服务器地址addr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[1]));server_addr.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(sock, (addr *)&server_addr, sizeof(server_addr)) != 0) {perror("bind");return -1;}listen(sock, 1000);printf("TCP server running\n");addr_in client_addr;socklen_t client_addr_len = sizeof(client_addr);int client_sock = accept(sock, (addr *)&client_addr, &client_addr_len);if (client_sock > 0) {client_info info;info.sock = client_sock;inet_ntop(AF_INET, &client_addr.sin_addr, info.ip, INET_ADDRSTRLEN);printf("Client connected: %s\n", info.ip);pthread_t read_tid, send_tid;pthread_create(&read_tid, NULL, readTask, &info);pthread_create(&send_tid, NULL, sendTask, &info);pthread_join(send_tid, NULL);}close(sock);return 0;
}

通过上述TCP网络编程的介绍和实例代码,读者可以掌握如何使用TCP协议进行可靠的数据通信,并根据实际需求实现功能丰富的网络应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/431812.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IDEA去除掉虚线,波浪线,和下划线实线的方法

初次安装使用IDEA&#xff0c;总是能看到导入代码后&#xff0c;出现很多的波浪线&#xff0c;下划线和虚线&#xff0c;这是IDEA给我们的一些提示和警告&#xff0c;但是有时候我们并不需要&#xff0c;反而会让人看着很不爽&#xff0c;这里简单记录一下自己的调整方法&#…

Ubunt系统设置NVIDIA显卡性能模式

文章目录 前言一、了解自己的显卡1、输入nvidia-smi指令搞清楚表中的含义 二、通过英伟达官方设置进行修改1、此时的状态3、改完后变为P0 总结 前言 工欲善其事&#xff0c;那性能直接拉满&#xff0c;宁可累坏显卡&#xff0c;也不能影响自己&#xff0c;首先了解自己的显卡以…

OpenAPI鉴权(二)jwt鉴权

一、思路 前端调用后端可以使用jwt鉴权&#xff1b;调用三方接口也可以使用jwt鉴权。对接多个三方则与每个third parth都约定一套token规则&#xff0c;因为如果使用同一套token&#xff0c;token串用可能造成权限越界问题&#xff0c;且payload交叉业务不够清晰。下面的demo包…

uni-app页面调用接口和路由(四)

文章目录 一、路由二、页面调用接口二、路由跳转1.uni.navigateTo(OBJECT)2.uni.redirectTo(OBJECT)3.uni.reLaunch(OBJECT)4.uni.switchTab(OBJECT)5.uni.navigateBack(OBJECT) 总结 一、路由 路由配置 uni-app页面路由为框架统一管理&#xff0c;开发者需要在pages.json里配…

iOS六大设计原则设计模式

六大设计原则&#xff1a; 一、单一职责原则 一个类或者模块只负责完成一个职责或者功能。 类似于&#xff1a;UIView 和 CALayer 二、开放封闭原则 对扩展开放&#xff0c;对修改封闭。 我们要尽量通过扩展软件实体来解决需求变化&#xff0c;而不是通过修改已有的代码来…

ESP32-WROOM-32 [创建AP站点-客户端-TCP透传]

简介 基于ESP32-WROOM-32 开篇(刚买)&#xff0c; 本篇讲的是基于固件 ESP32-WROOM-32-AT-V3.4.0.0&#xff08;内含用户指南, 有AT指令说明&#xff09;的TCP透传设置与使用 设备连接 TTL转USB线, 接ESP32 板 的 GND&#xff0c;RX2&#xff0c; TX2 指令介绍 注意,下面指…

Facebook Marketplace无法使用的原因及解决方案

Facebook Marketplace是一项广受欢迎的买卖平台&#xff0c;然而&#xff0c;有时候用户可能会遇到无法访问或使用该功能的问题。通常&#xff0c;这些问题可以归结为以下几类原因&#xff1a; 地理位置限制&#xff1a; Facebook Marketplace并非在全球每个地区都可用。在某些…

【C++】C++中如何处理多返回值

十四、C中如何处理多返回值 本部分也是碎碎念&#xff0c;因为这些点都是很小的点&#xff0c;构不成一篇文章&#xff0c;所以本篇就是想到哪个点就写哪个点。 1、C中如何处理多个返回值 写过python的同学都知道&#xff0c;当你写一个函数的返回时&#xff0c;那是你想返回…

MySQL(日志)

日志 日志分为三种&#xff1a; undo log &#xff08;回滚日志&#xff09;&#xff1a;用于事务回滚和MVCC redo log &#xff08;重做日志&#xff09;&#xff1a;用于故障恢复 binlog &#xff08;归档日志&#xff09;&#xff1a;用于数据备份和主从复制 undo log undo…

一个简单的个人博客管理平台适合新手学习(最底下有github链接)

一个简单的个人博客管理平台 欢迎大家一起学习 前端技术栈 vue3jshtmlcsselement-plus 后端技术栈 springbootredismysqlmybatis 首页展示 页面介绍 左边为文章界面点击文字名字就能进行阅读 右边为热门博客功能能够实时统计前五名博客热度并且将前三名展示在卡片中(卡片…

【人工智能学习之常用损失函数浅谈】

【人工智能学习之常用损失函数浅谈】 Focal Loss基本概念Focal Loss的定义作用应用场景 Arc Loss基本概念ArcFace Loss的定义作用应用场景 CenterLoss基本概念Center Loss 的定义作用应用场景实现细节 Cross Entropy Loss (CELoss)基本概念二分类任务多分类任务作用优点缺点应用…

oracle avg、count、max、min、sum、having、any、all、nvl的用法

组函数 having的使用 any的使用 all的使用 nvl 从执行结果来看&#xff0c;nvl(列名&#xff0c;默认值)&#xff0c;nvl的作用就是如果列名所在的这一行出现空则用默认值替换

D. Determine Winning Islands in Race (cf div2,dp、图论最短路)

D. Determine Winning Islands in Race 思路: bfs找到E到达每个点的最短时间t[i]。 如果E要超过B&#xff0c;那么一定要借助辅助桥&#xff0c;从而获胜。 假设有u->v的辅助桥&#xff0c;E能通过这个桥超过B的条件是: s>u 且 t[v] < v-s 即 s的取值要为[u1,v-t[v]-…

每天分享一个FPGA开源代码(6)- 浮点数运算

FPGA&#xff08;现场可编程门阵列&#xff09;是一种高度可配置的集成电路&#xff0c;它可以用于实现各种数字信号处理任务&#xff0c;包括浮点数运算。 在FPGA上进行浮点数运算通常涉及以下几个步骤&#xff1a; 1. 选择浮点数格式 浮点数运算首先要确定使用哪种浮点数格…

第二十八篇——用间篇:使用间谍,先学习花钱的价值观

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 间谍的本质&#xff0c;任何策略没有好坏没有道德&#xff0c;它是平衡路…

【大模型】AutoDL部署AI绘图大模型Stable Diffusion使用详解

目录 一、前言 二、AI绘图大模型概述 2.1 AI绘图大模型介绍 2.2 AI绘图大模型特点 2.3 AI绘图大模型优势 三、主流的AI绘图大模型介绍 3.1 Midjourney 3.1.1 Midjourney介绍 3.1.2 Midjourney功能特点 3.1.3 Midjourney使用场景 3.2 Stable Diffusion 3.2.1 Stable …

Unity中的功能解释(数学位置相关和事件)

向量计算 Vector3.Slerp&#xff08;起点坐标&#xff0c;终点坐标&#xff0c;t&#xff09;&#xff0c;可是从起点坐标以一个圆形轨迹到终点坐标&#xff0c;有那么多条轨迹&#xff0c;那怎么办 Vector3.Slerp 进行的是沿球面插值&#xff0c;因此并不是沿着严格的“圆形…

【LeetCode】146. LRU缓存

1.题目 2.思想 3.代码 3.1 代码1 下面这是一版错误的代码。错误的原因在于逻辑不正确导致最后的代码也是不正确的。 class LRUCache:def __init__(self, capacity: int):self.time 0 # 用于全局记录访问的时间self.num2time {} # 数字到时间的映射self.key2val {} # 数字…

大数据新视界 --大数据大厂之HBase 在大数据存储中的应用与表结构设计

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

.net core集成Minio,构建一个文件存储的基础设施

背景 先简单介绍下MinIO吧&#xff0c;官方给的介绍是它是一种高性能、S3 兼容的对象存储。它专为大规模 AI/ML、数据湖和数据库工作负载而构建&#xff0c;并且它是由软件定义的存储。不需要购买任何专有硬件&#xff0c;就可以在云上和普通硬件上拥有分布式对象存储。 MinI…