当前位置: 首页 > news >正文

代码详细注释:(linux)TCP客户端接收服务器端发的信息

服务器端代码

/*2 - TC服务器 */
#include <stdio.h>      // 标准输入输出库
#include <stdlib.h>     // 标准库函数
#include <unistd.h>     // Unix标准函数
#include <sys/socket.h> // 套接字相关函数
#include <sys/types.h>  // 系统数据类型
#include <fcntl.h>      // 文件控制
#include <sys/stat.h>   // 文件状态
#include <netinet/in.h> // 网络地址结构
#include <arpa/inet.h>  // IP地址转换函数int main(int argc,char *argv[])
{if(argc!=3){  // 检查参数数量是否正确printf("Usage:%s ip port\n",argv[0]);  // 打印使用方法exit(0);  // 退出程序}//1.创建socketint sockfd = socket(AF_INET,SOCK_STREAM,0);  // 创建IPv4 TCP套接字if(sockfd==-1){  // 检查socket创建是否成功perror("socket");  // 打印错误信息exit(-1);  // 异常退出}//2.绑定ip和端口号(自己)struct sockaddr_in addr;  // 定义IPv4地址结构addr.sin_family = AF_INET;  // 设置地址族为IPv4addr.sin_port = htons(atoi(argv[2]));  // 将端口号转换为网络字节序addr.sin_addr.s_addr = inet_addr(argv[1]);  // 将IP地址字符串转换为网络字节序int res = bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));  // 绑定套接字到指定地址if(res==-1){  // 检查绑定是否成功perror("bind");  // 打印错误信息exit(-1);  // 异常退出}//3.监听listen(sockfd,10);  // 开始监听,设置最大连接队列为10//4.等待客户端连接while(1){  // 无限循环,持续接受客户端连接struct sockaddr_in cilent_addr;  // 存储客户端地址信息socklen_t len = sizeof(cilent_addr);  // 客户端地址结构长度// 接受客户端连接int newfd = accept(sockfd,(struct sockaddr *)&cilent_addr,&len);if(newfd==-1){  // 检查连接是否成功perror("accept");  // 打印错误信息exit(-1);  // 异常退出}// 打印客户端IP地址printf("%s到此一游!\n",inet_ntoa(cilent_addr.sin_addr));//5.和客户端通信write(newfd,"hello",6);  // 向客户端发送"hello"消息//不再通信关闭close(newfd);  // 关闭与客户端的连接}close(sockfd);  // 关闭服务器套接字(实际上永远不会执行到这里)return 0;
}

主要流程说明:

  1. 参数检查:检查程序启动参数是否正确(需要IP和端口两个参数)

  2. 创建套接字:创建一个IPv4的TCP套接字

  3. 绑定地址:将套接字绑定到指定的IP地址和端口

  4. 开始监听:设置套接字为监听状态,准备接受客户端连接

  5. 接受连接:循环等待并接受客户端连接

  6. 处理连接:对于每个连接,打印客户端IP并发送"hello"消息

  7. 关闭连接:完成通信后关闭与客户端的连接

注意事项:

  • 服务器会一直运行,直到被手动终止

  • 每次只处理一个客户端连接,发送完消息后立即关闭连接

  • 实际应用中可能需要更复杂的错误处理和并发处理机制

 


 

客户端代码

#include <stdio.h>      // 标准输入输出函数
#include <stdlib.h>     // 标准库函数(如exit)
#include <unistd.h>     // Unix标准函数(如read, write, close)
#include <string.h>     // 字符串处理函数
#include <sys/socket.h> // 套接字相关函数和结构
#include <netinet/in.h> // 互联网地址族定义
#include <arpa/inet.h>  // IP地址转换函数// 定义常量
#define SERVER_IP "192.168.53.1"  // 服务器IP地址
#define SERVER_PORT 5555          // 服务器端口号
#define BUFFER_SIZE 1024          // 接收缓冲区大小int main() {// 1. 创建socket// AF_INET: IPv4协议, SOCK_STREAM: 流式套接字(TCP), 0: 默认协议int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1) {  // 检查socket是否创建成功perror("socket creation failed");  // 打印错误信息exit(EXIT_FAILURE);  // 退出程序并返回失败状态}// 2. 准备服务器地址结构struct sockaddr_in server_addr;  // 定义IPv4地址结构memset(&server_addr, 0, sizeof(server_addr));  // 清空结构体server_addr.sin_family = AF_INET;  // 设置地址族为IPv4server_addr.sin_port = htons(SERVER_PORT);  // 设置端口号(转换为网络字节序)// 将点分十进制IP转换为网络字节序的二进制形式server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);// 3. 连接到服务器// 参数:套接字描述符,服务器地址结构,结构体大小if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr))) {perror("connection failed");  // 连接失败时打印错误close(sockfd);  // 关闭套接字exit(EXIT_FAILURE);  // 退出程序}// 连接成功提示printf("Connected to server %s:%d\n", SERVER_IP, SERVER_PORT);// 4. 接收服务器消息char buffer[BUFFER_SIZE];  // 定义接收缓冲区// 从套接字读取数据,最大读取BUFFER_SIZE-1字节(保留位置给\0)ssize_t bytes_received = read(sockfd, buffer, BUFFER_SIZE - 1);if (bytes_received == -1) {  // 读取失败perror("read failed");} else if (bytes_received == 0) {  // 对端关闭连接printf("Server closed the connection\n");} else {  // 成功读取数据buffer[bytes_received] = '\0'; // 确保字符串以\0结尾printf("Received from server: %s\n", buffer);  // 打印接收到的消息}// 5. 关闭连接close(sockfd);  // 关闭套接字return 0;  // 正常退出程序
}

关键点详细说明:

  1. socket创建

    • AF_INET 表示使用IPv4协议

    • SOCK_STREAM 表示使用面向连接的TCP协议

    • 第三个参数0表示使用默认协议

  2. 地址结构准备

    • memset 清空结构体是良好的编程习惯

    • htons 将主机字节序的端口号转换为网络字节序

    • inet_addr 将点分十进制的IP字符串转换为网络字节序的二进制形式

  3. 连接过程

    • connect 是阻塞调用,会等待直到连接建立或失败

    • 连接失败时需要先关闭已创建的套接字再退出

  4. 数据接收

    • read 返回读取的字节数,-1表示错误,0表示连接关闭

    • 手动添加字符串终止符\0是安全的做法

  5. 资源清理

    • 程序退出前必须关闭套接字描述符

    • 这是良好的资源管理习惯

这个客户端实现了最基本的TCP连接功能,可以扩展添加发送数据、循环通信等功能。

 

http://www.lryc.cn/news/609520.html

相关文章:

  • AI 大模型分类全解析:从文本到多模态的技术图谱
  • Rust ⽣成 .wasm 的极致瘦⾝之道
  • 从 Hive 数仓出发,全面剖析 StarRocks、MySQL、HBase 的使用场景与区别
  • 【Spark征服之路-4.5-Spark-Streaming核心编程(三)】
  • [Oracle] TO_CHAR()函数
  • 安装MySQL教程时可能遇到的问题
  • 【Linux】重生之从零开始学习运维之GTID复制
  • XXE漏洞原理及利用
  • NSS-DAY17 2025SWPU-NSSCTF
  • Chrontel 【CH7103B-B】CH7103B HDMI to YPbPr Converter
  • 行业报告:.games域名正引领游戏娱乐产业营销新风向
  • 力扣 hot100 Day65
  • 嵌入式学习之51单片机——串口(UART)
  • 回归预测 | MATLAB实现BP神经网络多输入单输出回归预测+SHAP可解释分析
  • 分布式光伏气象站:为分散电站装上 “智慧之眼”
  • 零基础掌握 Scrapy 和 Scrapy-Redis:爬虫分布式部署深度解析
  • 分布式版本控制工具Git
  • Spring之【Bean的实例化方式】
  • 电脑忘记开机密码怎么办?【图文详解】5种方法重置/更改/取消/设置开机密码?
  • Java从入门到精通 - 算法、正则、异常
  • 深入浅出 RabbitMQ:简单队列实战指南
  • 【Linux指南】软件安装全解析:从源码到包管理器的进阶之路
  • 小杰数据结构(five day)——知人者智,自知者明。
  • WPF 按钮背景色渐变
  • 飞算 JavaAI:给需求分析装上 “智能大脑“
  • VPS云服务器Linux性能分析与瓶颈解决方案设计
  • 机器学习 决策树案例电信用户流失
  • 豆包新模型+PromptPilot深度评测:提示词工程的智能化突破
  • Chrontel 【CH7104B-BF】CH7104B HDMI to HDTV/VGA Converter
  • SJW-app-1