Linux Socket 编程实战:从可编译实例到多连接服务
简介这份资源面向Linux网络编程初学者与需要夯实Socket基础的开发者系统梳理了Socket通信的核心原理与常用接口。内容从网络中进程如何唯一标识讲起说明IP地址、协议与端口三元组的作用并解释Socket作为特殊文件的设计思想随后逐一介绍socket()、bind()、listen()、connect()、accept()、read()/write()及close()等基本操作配合TCP三次握手建立连接与四次挥手释放连接的详细过程最后给出一个可动手实践的服务端与客户端示例帮助读者把理论落到代码。资源包为1个docx文档约77KB结构紧凑适合作为随查随用的学习笔记或教学参考。目前已有241人学习内容覆盖从概念到实践的完整链路便于快速理解跨主机进程通信机制为后续开发Web服务器、聊天程序等网络应用打下基础。1. 从一份“转帖级”Socket 笔记说起它到底能不能跑起来很多人第一次搜 Linux Socket 编程翻到的都是同一类东西概念讲得挺全函数列了一堆真到编译运行就卡住。这份资源不一样它是一份带完整实例的转帖笔记原作者把 socket()、bind()、listen()、connect()、accept()、read()/write()、close() 这条链路串了一遍还配了一个能编译的 C 小工程mysocket 类封装服务端和客户端server.cpp 监听 6666 端口client.cpp 连上去发消息。它解决的不是“什么是 socket”这种科普问题而是“我照着写能不能跑通、跑不通该看哪一行”的落地问题。适合刚接触网络编程、想拿一份能直接编译的骨架改自己业务的人也适合工作几年但一直用框架、没亲手写过 accept 循环的人回头补课。2. 三元组与字节序Socket 通信绕不开的两个底层设定2.1 为什么是 IP 协议 端口而不是 PID本地进程通信靠 PID 就能定位但网络里 PID 只在单机内唯一跨主机就失效了。TCP/IP 给的方案是三元组IP 地址标识主机传输层协议加端口号标识主机上的应用进程。这三者组合起来才能在一堆并发连接里准确找到“这条数据该给谁”。理解这一点后面所有函数的行为就顺了。socket() 创建的是一个协议族空间里的“未命名端点”它知道自己属于 AF_INET 还是 AF_INET6但还没有具体地址。bind() 做的事就是把这个端点钉到某个 IP 和端口上。服务端必须 bind因为客户端需要一个众所周知的地址去连客户端通常不 bindconnect() 时内核会自动分配一个临时端口和本机 IP。这个不对称设计是很多新手第一次读代码时的困惑点。2.2 主机字节序转网络字节序一个曾引发血案的动作x86 是小端网络协议要求大端。你直接把sin_port 6666写进去在 x86 上跑起来可能“看起来正常”因为两端都是小端但一旦对端换成大端机器或者中间有设备按网络序解析端口号就完全错了。原笔记里那句“由于这个问题曾引发过血案”不是夸张我见过真实项目里因为漏了 htons调试了两天才定位到端口字段。正确做法是端口用htons()IPv4 地址用htonl()或inet_pton()不要对主机字节序做任何假定。下面这段是服务端 bind 前的标准准备动作struct sockaddr_in servaddr; memset(servaddr, 0, sizeof(servaddr)); servaddr.sin_family AF_INET; servaddr.sin_addr.s_addr htonl(INADDR_ANY); // 监听本机所有网卡 servaddr.sin_port htons(6666); // 端口必须转网络字节序INADDR_ANY表示不指定具体网卡 IP内核会帮你绑定到所有可用接口。如果你只想监听某一个网卡把htonl(INADDR_ANY)换成inet_pton(AF_INET, 192.168.1.18, servaddr.sin_addr)即可。参数上sin_family必须和 socket() 第一个参数一致sin_port和sin_addr必须走网络字节序memset清零不能省否则结构体里的填充字节可能是随机值。2.3 socket() 的三个参数怎么选socket(int domain, int type, int protocol)里domain 选 AF_INETIPv4或 AF_INET6type 选 SOCK_STREAMTCP或 SOCK_DGRAMUDPprotocol 一般填 0让系统根据 type 自动选默认协议。注意 type 和 protocol 不能乱配SOCK_STREAM 配 IPPROTO_UDP 是非法的。原实例里统一用socket(AF_INET, SOCK_STREAM, 0)这是 TCP 场景下最稳的写法。3. 把实例跑起来mysocket 类的编译、运行与参数调整3.1 文件结构与编译命令原实例给了四个文件mysocket.h、mysocket.cpp、server.cpp、client.cpp。server.h 和 client.h 是空的可以不管。编译时把 mysocket.cpp 分别和两个 main 一起编g -o server mysocket.cpp server.cpp g -o client mysocket.cpp client.cpp先起 server再起 client。server 会打印waiting for clients requestclient 连上后打印Begin sending msg to server然后循环发msg 0.、msg 1.这样的消息。server 端 recv 到后打印 connfd、消息内容和长度。3.2 客户端 IP 必须改原代码里写死了192.168.1.18这是最容易翻车的地方。如果你在本机测试改成127.0.0.1如果 server 在另一台机器改成那台机器的实际 IP。改的位置在createclient里的inet_pton调用// 本机测试用 127.0.0.1跨机测试换成 server 实际 IP if( inet_pton(AF_INET, 127.0.0.1, servaddr.sin_addr) 0){ printf(inet_pton error\n); return false; }inet_pton返回 1 表示成功0 表示地址格式不对-1 表示协议族不支持。比老的inet_addr好在能明确区分错误类型也不会把255.255.255.255误判为失败。3.3 accept 循环与 recv 循环的写法问题原实例的recvmsg()里accept 失败会 continue成功就 break 出 while(1)然后进入 recv 循环。这个写法只能处理一个客户端第二个客户端连上来时第一个连接没断accept 就不会再被调用。作为教学 demo 够用但你要改成能并发服务至少得把 accept 放进循环每个连接 fork 一个子进程或开线程。recv 循环里有个细节memset(buff, 0, 1024)放在 recv 之后、打印之前但buff[n] \0又依赖 n 是上一次 recv 的返回值。实际执行顺序是 recv 返回 n然后 memset 清空再buff[n] \0这会把第 n 个字节置零但前面 recv 写进去的数据已经被 memset 清掉了。正确顺序应该是先 recv再置零末尾再打印再清空。这个 bug 在原笔记里没被指出但你自己改的时候要注意。while((n recv(connfd, buff, 1023, 0)) 0){ buff[n] \0; // 先保证字符串结束 printf(recv: %s, len%d\n, buff, n); memset(buff, 0, 1024); // 再清空准备下一次 }recv 返回 0 表示对端关闭了连接返回 -1 表示出错需要看 errno。EINTR 表示被信号中断可以重试ECONNRESET 表示连接被对端重置。3.4 send 的返回值处理原实例的sedmsg()里send 返回值小于 0 时打印错误然后 continue没有区分 EINTR 和 EPIPE。EPIPE 表示对端已经关闭继续发没有意义应该 break 退出循环。EINTR 可以重试。另外 send 返回值大于 0 但不等于 strlen(buff) 时表示只发了一部分严格来说需要循环发送剩余部分。demo 里消息短一次发完的概率高但生产代码不能省这个判断。4. 三次握手与四次挥手connect 和 accept 到底卡在哪一步4.1 connect 在第二次握手返回accept 在第三次返回这是原笔记里最有价值的一句话。客户端调 connect 时内核发 SYN Jconnect 阻塞服务端收到 SYN Jaccept 被唤醒发 SYN K ACK J1accept 继续阻塞客户端收到 SYN K ACK J1connect 返回同时发 ACK K1服务端收到 ACK K1accept 返回。所以 connect 返回时连接对客户端来说已经建立accept 返回时服务端才拿到已连接 socket。理解这个时序你就能解释为什么有时候客户端 connect 成功了但服务端 accept 还没返回——第三次握手包还在路上。也能解释为什么 listen 的 backlog 参数重要如果半连接队列满了新的 SYN 会被丢弃客户端会重试。4.2 close 与引用计数close 一个 TCP socket 时如果引用计数不为 0不会立即发 FIN。只有最后一个引用被 close 时才触发四次挥手。这意味着如果你 fork 之后父子进程都持有同一个 socket父进程 close 不会关闭连接子进程还得再 close 一次。这个行为在写多进程服务器时经常被忽略导致连接泄漏。四次挥手的过程是主动关闭方发 FIN M被动方回 ACK M1同时把 FIN 作为文件结束符传给应用进程被动方处理完数据后 close发 FIN N主动方回 ACK N1。主动方最后会进入 TIME_WAIT 状态等 2MSL 才真正关闭。TIME_WAIT 是为了保证最后一个 ACK 能到达对端如果对端没收到会重发 FIN主动方还能再回一次 ACK。5. 避坑与排查这份实例改到能用之前会遇到的五件事5.1 bind 报 Address already in use现象server 刚跑完一次再启动就 bind 失败提示bind socket error。原因上一次的连接还处于 TIME_WAIT端口被占用。解决在 bind 之前加setsockopt设置 SO_REUSEADDRint opt 1; setsockopt(m_isocket, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt));这个选项让内核允许绑定处于 TIME_WAIT 的端口是服务端代码的标配。5.2 客户端 connect 返回 Connection refused现象client 启动后立刻报connect to server error。原因server 没起或者 IP/端口写错或者防火墙拦了。解决先确认 server 在跑netstat -an | grep 6666看端口是否 LISTEN再确认 client 里的 IP 是 server 实际可达的地址本机测试用 127.0.0.1跨机测试确认网络连通。5.3 recv 收到乱码或长度不对现象server 打印的消息末尾有奇怪字符或者长度比预期大。原因recv 不保证按消息边界返回TCP 是字节流。你发两次msg 0.和msg 1.对端可能一次 recv 收到两条拼在一起。解决demo 里消息短且发送间隔小不容易复现但生产代码必须自己定协议比如固定长度、或者长度前缀、或者分隔符。原实例用\n结尾但没有按行解析只是打印所以看起来正常。5.4 accept 返回 -1 且 errno 为 EMFILE现象并发连接多了之后accept 开始失败errno 是 EMFILE。原因进程打开的文件描述符达到上限。每个 accept 返回的 connfd 都占一个 fd如果只 accept 不 close很快耗尽。解决ulimit -n看当前限制用close(connfd)及时关闭或者调大限制。原实例的 recv 循环里没有 close connfd客户端断开后 connfd 也没关长时间跑会泄漏。5.5 编译报 sockaddr_in 未定义现象g报storage size of servaddr isnt known或sockaddr_in was not declared。原因缺少头文件。原实例的 mysocket.cpp 里包含了netinet/in.h但如果你自己拆代码容易漏。解决确保包含sys/socket.h、netinet/in.h、arpa/inet.h。顺序上sys/socket.h要在netinet/in.h之前否则某些平台会报错。6. 从 demo 到可用把 mysocket 改成多连接服务的三个动作原实例只能服务一个客户端改到能同时处理多个连接最直接的办法是 accept 之后 fork 子进程。父进程继续 accept子进程处理 recv/send处理完 close connfd 退出。这样每个连接独立互不阻塞。但 fork 有代价进程创建开销、父子进程通信麻烦。更现代的做法是 epoll 或线程池不过那是另一个话题了。如果你只想先验证多连接fork 版最快。改动点在recvmsg()while(1){ int connfd accept(m_isocket, NULL, NULL); if(connfd -1){ continue; } if(fork() 0){ close(m_isocket); // 子进程不需要监听 socket char buff[1024]; int n; while((n recv(connfd, buff, 1023, 0)) 0){ buff[n] \0; printf(child recv: %s\n, buff); } close(connfd); // 子进程关闭已连接 socket exit(0); } close(connfd); // 父进程关闭已连接 socket引用计数减一 }这里有个关键点父进程 accept 返回的 connfd 和子进程继承的 connfd 指向同一个连接父进程必须 close 掉自己的那份否则引用计数不归零连接不会真正关闭。子进程也要 close 监听 socket否则监听 fd 泄漏。验证方法起 server同时起三个 clientserver 端应该能同时收到三路消息。用ps -ef | grep server能看到多个子进程。netstat -an | grep 6666能看到多个 ESTABLISHED 连接。从那以后我每次写 socket 服务端都会先把 SO_REUSEADDR、字节序转换、accept 循环、connfd 关闭这四件事过一遍再往下写业务逻辑。这份笔记的实例不算完美但它把从 socket() 到 close() 的完整链路摆出来了改一改就能当脚手架用。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

微信小程序远程在线诊疗系统:基于SSM的完整设计与实现

微信小程序远程在线诊疗系统:基于SSM的完整设计与实现

简介:面向高校毕业设计场景的微信小程序远程在线诊疗系统完整项目,后端采用Java SSM框架与MySQL数据库,前端为微信开发者工具构建的小程序,并辅以Vue相关后台管理界面。系统内设管理员、用户、医生三类角色,覆盖科室信…

2026/10/18 10:36:45 阅读更多 →
勇士传说横版卷轴游戏:C#动作游戏源码解析与毕业设计实战

勇士传说横版卷轴游戏:C#动作游戏源码解析与毕业设计实战

简介:这份资源是基于C#开发的「勇士传说」横版卷轴游戏完整源码,面向计算机相关专业做毕业设计的学生,以及希望入门Unity 2D游戏开发的学习者。项目以经典横版卷轴玩法为核心,涵盖角色动画、碰撞检测、地图设计、敌人AI与用户输入…

2026/10/18 10:36:45 阅读更多 →
零基础参与开源Python项目:从Fork到首个PR的完整实战指南

零基础参与开源Python项目:从Fork到首个PR的完整实战指南

1. 先搞清楚开源贡献这件事,远不止写代码很多刚接触开源Python项目的人,以为“做贡献”就等于“提PR改源码”。我最初也是这样想的,甚至一度觉得,自己没写出过有设计感的代码,就不配去动别人的仓库。直到后来真正参与进…

2026/10/18 10:35:45 阅读更多 →

最新新闻

XMLViewer:高效处理大文件XML的树形查看与搜索工具

XMLViewer:高效处理大文件XML的树形查看与搜索工具

简介:XMLViewer 是一款面向开发人员与运维人员的专业 XML 查看工具,主要解决日常排查 XML 文件语法是否正确、结构是否清晰的问题。安装完成后,只需右键点击 XML 文件并选择“View”,即可快速打开查看,省去手动配置编辑…

2026/10/18 11:17:01 阅读更多 →
按键脚本与智能辅助深度对比:一个自动化项目的真实踩坑实录

按键脚本与智能辅助深度对比:一个自动化项目的真实踩坑实录

做自动化这几年,我被人问得最多的一句话就是:“做这种自动点击、自动录入的活儿,到底用传统按键脚本,还是用那种带图像识别、带‘智能’二字的辅助工具?”说实话,这个问题没有标准答案,但有一个…

2026/10/18 11:17:01 阅读更多 →
DNS与CDN协同工作:从CNAME调度到缓存回源的运维排查指南

DNS与CDN协同工作:从CNAME调度到缓存回源的运维排查指南

1. 从一次页面访问说起:先搞清楚DNS和CDN分别在忙什么很多人对DNS的理解停留在“把www开头的域名翻译成IP地址”这一步,对CDN的理解停留在“把静态文件缓存到离用户近的服务器”这一步。这两句话没错,但远远不够。如果你手里正好有一个域名要…

2026/10/18 11:17:01 阅读更多 →
SSM + MySQL + JSP 的小区物业管理系统设计与部署全解析

SSM + MySQL + JSP 的小区物业管理系统设计与部署全解析

简介:一款基于SSM框架和MySQL数据库的双星小区物业管理系统完整源码包,面向Java学习者、毕业设计开发者以及需要快速搭建后台管理系统的工程技术人员。系统整合Spring、SpringMVC、MyBatis与Maven,前端采用JSP、CSS、JavaScript,包…

2026/10/18 11:17:01 阅读更多 →
工控系统选型指南:Windows、Linux与安卓的适用场景与避坑实践

工控系统选型指南:Windows、Linux与安卓的适用场景与避坑实践

1. 三种工控系统的基本盘与选型逻辑工业控制这个圈子有个很有意思的现象:做PLC的人觉得上位机用什么系统无所谓,做视觉检测的人为了一个相机驱动能折腾三天,而做产线MES对接的人则天天祈祷现场那台工控机别蓝屏。这三种焦虑背后,其…

2026/10/18 11:17:01 阅读更多 →
YOLOv8鸡蛋检测项目实战:从数据标注、一键训练到Web部署的完整链路

YOLOv8鸡蛋检测项目实战:从数据标注、一键训练到Web部署的完整链路

做目标检测项目的同学,尤其是一上来就打算拿YOLOv8搞定制化检测的,普遍会卡在同样的三座山上:一是没有一套能直接用的已标注数据集,标注成本极高,自己从零标几百张图就标得想吐;二是训练流程繁琐&#xff0…

2026/10/18 11:16:01 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/16 14:23:36 阅读更多 →