当前位置: 首页 > 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.dtcms.com/a/314081.html

相关文章:

  • SAP-ABAP:SAP Open SQL 分页技术深度解析:语法、性能陷阱与最佳实践
  • React配置proxy跨域
  • 【异常案例分析】使用空指针调用函数(非虚函数)时,没有崩溃在函数调用处,而是崩在被调用函数内部
  • 用Streamlit、Pandas与Plotly打造交互式数据可视化仪表盘:从零到一的实战教程
  • 【unitrix】 7.2 二进制位减法(bit_sub.rs)
  • 认识爬虫 —— xpath提取
  • ML307模组 OpenCPU 软件调试
  • Oracle 定时任务相关
  • 计算机网络:有路由器参与的子网间通信原理
  • [spring-cloud: NamedContextFactory ClientFactoryObjectProvider]-源码阅读
  • SparkSQL—sequence 函数用法详解
  • 无人机路径规划技术要点与难点分析
  • 权限管理命令
  • 【C++】2. 类和对象(上)
  • Anthropic 禁止 OpenAI 访问 Claude API:商业竞争与行业规范的冲突
  • mongodb源代码分析创建db流程分析
  • 芯脑觉醒:Deepoc如何让送餐机器人“活”起来?
  • 手搓TCP服务器实现基础IO
  • Go语言高并发价格监控系统设计
  • TCP 协议的“无消息边界”(No Message Boundaries)特性
  • sqli-labs-master/Less-31~Less-40
  • 内联函数:提升效率的空间换时间艺术
  • 移动端 WebView 视频无法播放怎么办 媒体控件错误排查与修复指南
  • 官宣!多功能DC-DC数字电源控制器重磅首发
  • 应用药品GSP证书识别技术,提升药品流通各环节的合规管理效率和风控水平
  • 数据工程与处理:AI时代的数据基石与智能化管道
  • java~final关键字
  • doris `unicode` 是多语言混合类型分词与elasticsearch分词差异
  • Java从入门到精通 - 算法、正则、异常
  • MQTT:安装部署