首页/新闻资讯/正文详情

Linux网络编程:TCP与UDP计算器实现对比

发布时间:2026/11/15 4:44:52 来源:云帆数科 栏目:资讯中心
Linux网络编程:TCP与UDP计算器实现对比
1. 项目背景与核心目标在Linux网络编程中TCP和UDP是两种最基础的传输层协议。TCP提供可靠的、面向连接的通信而UDP则是无连接的、尽最大努力交付的协议。通过实现一个简单的计算器服务我们可以深入理解这两种协议在实际应用中的差异和适用场景。这个项目的主要目标是实现基于TCP协议的计算器服务端和客户端实现基于UDP协议的计算器服务端和客户端对比两种协议在实现相同功能时的差异掌握Linux下socket编程的基本方法2. TCP服务端实现详解2.1 TCP服务端核心流程TCP服务端的基本工作流程如下创建socket使用socket()系统调用创建一个TCP socket绑定地址使用bind()将socket绑定到特定的IP地址和端口监听连接使用listen()开始监听连接请求接受连接使用accept()接受客户端的连接数据交换使用read()/write()或send()/recv()进行数据收发关闭连接使用close()关闭连接2.2 关键代码实现#include stdio.h #include stdlib.h #include string.h #include unistd.h #include sys/types.h #include sys/socket.h #include netinet/in.h #define PORT 8080 int main() { int sockfd, newsockfd; socklen_t clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; // 1. 创建socket sockfd socket(AF_INET, SOCK_STREAM, 0); if (sockfd 0) { perror(ERROR opening socket); exit(1); } // 2. 绑定地址 bzero((char *) serv_addr, sizeof(serv_addr)); serv_addr.sin_family AF_INET; serv_addr.sin_addr.s_addr INADDR_ANY; serv_addr.sin_port htons(PORT); if (bind(sockfd, (struct sockaddr *) serv_addr, sizeof(serv_addr)) 0) { perror(ERROR on binding); exit(1); } // 3. 监听连接 listen(sockfd, 5); clilen sizeof(cli_addr); while (1) { // 4. 接受连接 newsockfd accept(sockfd, (struct sockaddr *) cli_addr, clilen); if (newsockfd 0) { perror(ERROR on accept); continue; } // 5. 数据交换 bzero(buffer, 256); int n read(newsockfd, buffer, 255); if (n 0) { perror(ERROR reading from socket); close(newsockfd); continue; } // 处理计算请求 int num1, num2; char op; sscanf(buffer, %d %c %d, num1, op, num2); int result; switch(op) { case : result num1 num2; break; case -: result num1 - num2; break; case *: result num1 * num2; break; case /: result num1 / num2; break; default: result 0; } sprintf(buffer, %d, result); n write(newsockfd, buffer, strlen(buffer)); if (n 0) { perror(ERROR writing to socket); } // 6. 关闭连接 close(newsockfd); } close(sockfd); return 0; }2.3 TCP实现注意事项连接管理TCP是面向连接的协议每个客户端连接都需要独立的socket处理错误处理每个系统调用都可能失败必须检查返回值并适当处理错误字节序转换网络字节序是大端序需要使用htons/htonl等函数进行转换并发处理上述代码是单线程的实际应用中可能需要多线程或IO多路复用3. UDP服务端实现详解3.1 UDP服务端核心流程UDP服务端的工作流程比TCP简单创建socket使用socket()系统调用创建一个UDP socket绑定地址使用bind()将socket绑定到特定的IP地址和端口接收数据使用recvfrom()接收客户端数据发送响应使用sendto()发送响应数据重复步骤3-4处理后续请求3.2 关键代码实现#include stdio.h #include stdlib.h #include string.h #include unistd.h #include sys/types.h #include sys/socket.h #include netinet/in.h #define PORT 8080 int main() { int sockfd; socklen_t clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; // 1. 创建socket sockfd socket(AF_INET, SOCK_DGRAM, 0); if (sockfd 0) { perror(ERROR opening socket); exit(1); } // 2. 绑定地址 bzero((char *) serv_addr, sizeof(serv_addr)); serv_addr.sin_family AF_INET; serv_addr.sin_addr.s_addr INADDR_ANY; serv_addr.sin_port htons(PORT); if (bind(sockfd, (struct sockaddr *) serv_addr, sizeof(serv_addr)) 0) { perror(ERROR on binding); exit(1); } while (1) { // 3. 接收数据 clilen sizeof(cli_addr); bzero(buffer, 256); int n recvfrom(sockfd, buffer, 255, 0, (struct sockaddr *) cli_addr, clilen); if (n 0) { perror(ERROR in recvfrom); continue; } // 处理计算请求 int num1, num2; char op; sscanf(buffer, %d %c %d, num1, op, num2); int result; switch(op) { case : result num1 num2; break; case -: result num1 - num2; break; case *: result num1 * num2; break; case /: result num1 / num2; break; default: result 0; } sprintf(buffer, %d, result); // 4. 发送响应 n sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *) cli_addr, clilen); if (n 0) { perror(ERROR in sendto); } } close(sockfd); return 0; }3.3 UDP实现注意事项无连接特性UDP不需要建立连接每个数据包都是独立的数据包边界UDP保留数据包边界recvfrom()一次读取一个完整的数据包可靠性问题UDP不保证数据可靠传输应用层需要处理丢包和乱序问题最大报文长度UDP单次传输的数据量不应超过MTU(通常1500字节)4. 客户端实现与协议对比4.1 TCP客户端实现#include stdio.h #include stdlib.h #include unistd.h #include string.h #include sys/types.h #include sys/socket.h #include netinet/in.h #include netdb.h #define PORT 8080 int main(int argc, char *argv[]) { int sockfd; struct sockaddr_in serv_addr; struct hostent *server; char buffer[256]; if (argc 3) { fprintf(stderr,usage %s hostname operation\n, argv[0]); exit(0); } // 创建socket sockfd socket(AF_INET, SOCK_STREAM, 0); if (sockfd 0) { perror(ERROR opening socket); exit(1); } server gethostbyname(argv[1]); if (server NULL) { fprintf(stderr,ERROR, no such host\n); exit(0); } bzero((char *) serv_addr, sizeof(serv_addr)); serv_addr.sin_family AF_INET; bcopy((char *)server-h_addr, (char *)serv_addr.sin_addr.s_addr, server-h_length); serv_addr.sin_port htons(PORT); // 建立连接 if (connect(sockfd, (struct sockaddr *) serv_addr, sizeof(serv_addr)) 0) { perror(ERROR connecting); exit(1); } // 发送请求 printf(Please enter the operation (e.g. 1 2): ); bzero(buffer, 256); fgets(buffer, 255, stdin); int n write(sockfd, buffer, strlen(buffer)); if (n 0) { perror(ERROR writing to socket); exit(1); } // 接收响应 bzero(buffer, 256); n read(sockfd, buffer, 255); if (n 0) { perror(ERROR reading from socket); exit(1); } printf(Result: %s\n, buffer); close(sockfd); return 0; }4.2 UDP客户端实现#include stdio.h #include stdlib.h #include unistd.h #include string.h #include sys/types.h #include sys/socket.h #include netinet/in.h #include netdb.h #define PORT 8080 int main(int argc, char *argv[]) { int sockfd; struct sockaddr_in serv_addr; struct hostent *server; char buffer[256]; socklen_t servlen sizeof(serv_addr); if (argc 3) { fprintf(stderr,usage %s hostname operation\n, argv[0]); exit(0); } // 创建socket sockfd socket(AF_INET, SOCK_DGRAM, 0); if (sockfd 0) { perror(ERROR opening socket); exit(1); } server gethostbyname(argv[1]); if (server NULL) { fprintf(stderr,ERROR, no such host\n); exit(0); } bzero((char *) serv_addr, sizeof(serv_addr)); serv_addr.sin_family AF_INET; bcopy((char *)server-h_addr, (char *)serv_addr.sin_addr.s_addr, server-h_length); serv_addr.sin_port htons(PORT); // 发送请求 printf(Please enter the operation (e.g. 1 2): ); bzero(buffer, 256); fgets(buffer, 255, stdin); int n sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *) serv_addr, servlen); if (n 0) { perror(ERROR in sendto); exit(1); } // 接收响应 bzero(buffer, 256); n recvfrom(sockfd, buffer, 255, 0, (struct sockaddr *) serv_addr, servlen); if (n 0) { perror(ERROR in recvfrom); exit(1); } printf(Result: %s\n, buffer); close(sockfd); return 0; }4.3 TCP与UDP协议对比特性TCPUDP连接方式面向连接无连接可靠性可靠传输有确认机制不可靠传输无确认顺序保证保证数据顺序不保证顺序流量控制有滑动窗口机制无流量控制拥塞控制有拥塞控制算法无拥塞控制头部大小较大(20字节)较小(8字节)传输效率较低较高适用场景文件传输、网页浏览等需要可靠传输的场景视频流、DNS查询等实时性要求高的场景5. 项目扩展与优化建议5.1 并发处理优化当前的TCP服务端实现是单线程的只能同时处理一个客户端连接。可以通过以下方式改进多线程为每个客户端连接创建一个新线程多进程使用fork()为每个客户端创建子进程IO多路复用使用select/poll/epoll实现单线程处理多个连接5.2 协议设计优化当前实现使用简单的空格分隔格式传输计算表达式可以考虑使用JSON等结构化数据格式添加协议版本号增加错误码和错误信息返回5.3 安全性考虑添加输入验证防止缓冲区溢出实现简单的认证机制考虑使用TLS加密通信5.4 性能测试与调优使用工具如iperf测试吞吐量调整socket缓冲区大小测试不同并发量下的性能表现在实际项目中选择TCP还是UDP取决于具体需求。如果需要可靠传输TCP是更好的选择如果对实时性要求高且可以容忍少量丢包UDP可能更合适。通过这个简单的计算器项目我们可以清晰地看到两种协议在实际应用中的差异和各自的适用场景。

相关推荐

COMSOL与AI结合的光子器件智能设计实践
COMSOL与AI结合的光子器件智能设计实践

1. 项目概述:当COMSOL遇上AI的光子学革命十年前我刚开始接触光子器件设计时,手工调整波导参数就像在迷宫里摸黑前行。直到三年前第一次尝试将COMSOL的物理仿真与AI算法结合,才发现原来设计效率可以提升一个数量级。这种融合不是简单的工具叠加… · 2026/11/3 2:22:07

3托3恒压供水系统设计与节能优化实践
3托3恒压供水系统设计与节能优化实践

1. 项目概述:3托3恒压供水系统的核心价值这套"3托3"恒压供水系统是工业与民用领域供水解决方案的典型配置,由三台主泵、三台辅泵构成智能联动体系。我在某工业园区改造项目中首次采用这种架构,实测节能效率达到32%,压力… · 2026/11/12 11:57:31

哈希表与双指针:从两数之和到三数之和的算法解析
哈希表与双指针:从两数之和到三数之和的算法解析

1. 哈希表基础与两数之和解法哈希表(Hash Table)作为数据结构中的经典存在,本质上是通过键值对(key-value)存储数据的结构。它的核心优势在于平均O(1)时间复杂度的查找效率,这使其成为解决快速查找类问题的… · 2026/11/3 8:27:28

电工作业许证丢了怎么补办,真实经历告诉你怎么解决
电工作业许证丢了怎么补办,真实经历告诉你怎么解决

电工作业许证丢了怎么补办,真实经历告诉你怎么解决 你是不是也遇到过这种情况,手头的电工作业许证找不到了,心里一慌,不知道怎么补办,还担心自己学历不高报不上名?别急,我以前也经历过,现在就告诉你怎么解决。… · 2026/11/15 4:44:45

考电工证要打卡吗?通过率揭秘让你少走弯路
考电工证要打卡吗?通过率揭秘让你少走弯路

考电工证要打卡吗?通过率揭秘让你少走弯路 急需特种作业证才能上岗找工作,这事儿真不是闹着玩的。特别是电工证,不管是低压还是高压,都关系到你能不能顺利拿到工作机会。今天我就来聊聊, 考电工证要打卡吗… · 2026/11/15 4:44:45

驻马店电工证难不难 官方回应帮你理清真相
驻马店电工证难不难 官方回应帮你理清真相

驻马店电工证难不难 官方回应帮你理清真相 工地太忙根本没时间复习考试,这几乎是每个一线工友的常态,尤其是像电工这样需要持证上岗的岗位,考证成了绕不开的坎。不少人在驻马店地区报考电工证时,都会担心“驻马店电工证难不难”,其实官方回应已经给出了… · 2026/11/15 4:44:45

广东去哪里报考电工证值不值得考?怕考不过白交培训费
广东去哪里报考电工证值不值得考?怕考不过白交培训费

广东去哪里报考电工证值不值得考?怕考不过白交培训费 怕考不过白交培训费?别让3000块打水漂!你要是刚拿到电工证或者准备报考,肯定最怕的就是钱花了、时间花了,结果考试不过。别急,咱们今天就聊聊【广东去哪里报考电工证】,顺便解答你关心的“值不… · 2026/11/15 4:44:45

特种作业操作证升初级怎么考?学历不高怕报不上名?上岗必备信息全在这
特种作业操作证升初级怎么考?学历不高怕报不上名?上岗必备信息全在这

特种作业操作证升初级怎么考?学历不高怕报不上名?上岗必备信息全在这 你是不是也经常听别人说,特种作业操作证是上岗必备,但又担心自己学历不够,根本报不了名?其实,很多人都有这种顾虑,尤其是学历不高但想在建筑、电力、焊接等行业闯出一片天的朋友们… · 2026/11/15 4:44:45

电工证重新考试要多久网上查询最快补办流程全解析
电工证重新考试要多久网上查询最快补办流程全解析

电工证重新考试要多久网上查询最快补办流程全解析 实操考试心里没底怕挂科,这事儿真不是吹,好多电工朋友都遇到过。尤其是证书丢了或者到期了,重新考试流程复杂、时间又紧,心里没个数,干着急。今天就从 焦作劳务班组负责人 的角度,给你说清楚… · 2026/11/15 4:43:44

长春初级电工证怎么考?通过率揭秘全在这里
长春初级电工证怎么考?通过率揭秘全在这里

长春初级电工证怎么考?通过率揭秘全在这里 之前考的证在外省能不能转过来?这几乎是每个想从事电工工作的人都会问的问题。特别是那些在外地打拼多年、手里握着一张“外地电工证”的人,到了长春想继续干这一行,第一反应就是“我的证能用吗?”。今天我们就… · 2026/11/15 0:00:50

国内电工证报考条件与考试时间
国内电工证报考条件与考试时间

低压电工证怎么考?学历不高也能报名,官方报名入口全在这 你是不是经常听说“电工证是入行门槛”,但又担心自己学历不够、经验不足,根本报不了名?别急,今天就带你从零了解【国内电工证】的报考流程、考试内容,还有怎么在 官方报名入口… · 2026/11/15 0:00:50

电工作业时如何断电?电子证书到底能不能全国通用?
电工作业时如何断电?电子证书到底能不能全国通用?

电工作业时如何断电?电子证书到底能不能全国通用? 实操考试心里没底怕挂科,特别是电工作业时如何断电这一操作,不仅关系到你能不能拿到证书,更关系到以后能不能顺利上岗。很多人觉得这不过就是“断个电”,但其实这里面的门道可不少,稍有不慎就可能出错… · 2026/11/15 0:00:50

长春初级电工证怎么考?通过率揭秘全在这里
长春初级电工证怎么考?通过率揭秘全在这里

长春初级电工证怎么考?通过率揭秘全在这里 之前考的证在外省能不能转过来?这几乎是每个想从事电工工作的人都会问的问题。特别是那些在外地打拼多年、手里握着一张“外地电工证”的人,到了长春想继续干这一行,第一反应就是“我的证能用吗?”。今天我们就… · 2026/11/15 0:00:50

国内电工证报考条件与考试时间
国内电工证报考条件与考试时间

低压电工证怎么考?学历不高也能报名,官方报名入口全在这 你是不是经常听说“电工证是入行门槛”,但又担心自己学历不够、经验不足,根本报不了名?别急,今天就带你从零了解【国内电工证】的报考流程、考试内容,还有怎么在 官方报名入口… · 2026/11/15 0:00:50

电工作业时如何断电?电子证书到底能不能全国通用?
电工作业时如何断电?电子证书到底能不能全国通用?

电工作业时如何断电?电子证书到底能不能全国通用? 实操考试心里没底怕挂科,特别是电工作业时如何断电这一操作,不仅关系到你能不能拿到证书,更关系到以后能不能顺利上岗。很多人觉得这不过就是“断个电”,但其实这里面的门道可不少,稍有不慎就可能出错… · 2026/11/15 0:00:50

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 1:51:20

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 4:02:19

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 3:02:05

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码