96SEO 2026-02-19 22:33 0
1.1、socket1.2、bind1.3、recvfrom1.4、sendto2.1、代码2.1、说明3.1、代码3.2、说明

在前几篇博客中我们学习了Linux网络编程中的一些概念。
从本篇博客开始我们就正式开始写代码。
本篇博客我们将写udp服务器和客户端代码并实现服务器和客户端通信。
这些代码学习成本较高建议大家多敲几遍。
如任何问题欢迎与我沟通。
Protocol用户数据报协议和TCP协议Transmission
Protocol传输控制协议是计算机网络中两种常用的传输层协议它们在多个方面存在显著的异同。
以下是对两者异同点的详细比较
层次位置两者都位于OSI模型的第四层——传输层为上层应用提供数据传输服务。
作用都在网络通信中扮演着重要的角色用于在网络中的不同设备之间传输数据。
UDP协议TCP协议可靠性不提供可靠性保证不保证数据包的顺序、完整性和不重复。
提供可靠的数据传输通过序列号、确认机制和重传机制确保数据的完整性和有序性。
连接性无连接协议发送数据前不需要建立连接直接发送数据。
面向连接的协议数据传输前需要建立连接通过“三次握手”机制确认连接状态。
传输效率传输效率高因为不需要建立连接和维持连接状态开销小。
传输效率相对较低因为需要建立和维护连接增加了额外的开销。
实时性实时性较好适用于对实时性要求较高的应用如在线游戏、视频通话等。
实时性较差因为需要等待连接建立和确认以及处理重传等机制。
数据包大小数据包大小没有限制但通常受限于网络MTU最大传输单元。
将数据分割成较小的数据块进行传输以适应不同的网络环境。
拥塞控制不使用拥塞控制网络拥塞时不会降低发送速率。
使用拥塞控制机制根据网络状况调整发送速率避免网络拥塞。
应用场景适用于对可靠性要求不高但对实时性要求较高的场景如流媒体传输、DNS查询等。
适用于对可靠性要求较高的场景如文件传输、网页浏览等。
UDP协议和TCP协议在可靠性、连接性、传输效率、实时性、数据包大小和拥塞控制等方面存在显著的差异。
选择哪种协议取决于具体的应用场景和需求。
如果对数据传输的可靠性要求较高应选择TCP协议如果对实时性要求较高且可以容忍一定的数据丢失则可以选择UDP协议。
在实际应用中两种协议经常结合使用以满足不同的网络需求。
不难发现Udp代码较简单,写起来相对的简单一些上手较容易。
所以我们写使用Udp协议进行通信。
为了使大家更加容易理解。
我们按照创建udp服务端的整个过程的先后顺序来进行讲解。
最后写出完整的代码。
网络通信必须要申请套接字。
申请套接字对应的函数为socket。
domain协议域/协议族决定了socket的地址类型。
常用的协议族有AF_INETIPv4、AF_INET6IPv6、AF_LOCAL或称AF_UNIXUnix域socket、AF_ROUTE等。
在通信中必须采用与协议族对应的地址。
例如AF_INET决定了要使用IPv4地址32位与端口号16位的组合。
typesocket类型指定了socket的类型。
常用的socket类型有SOCK_STREAM流式套接字用于TCP、SOCK_DGRAM数据报套接字用于UDP、SOCK_RAW原始套接字允许对底层协议如IP或ICMP进行直接访问等。
protocol协议通常情况下可以将其设置为0让系统自动选择type类型对应的默认协议。
当socket函数成功创建了一个套接字时它返回一个有效的套接字描述符socket
descriptor。
这个描述符是一个非负整数用于后续的网络操作如绑定、监听、连接、发送和接收数据等。
如果在创建套接字时发生错误socket函数返回-1并设置全局变量errno以指示错误原因。
此时可以调用errno变量或perror()函数来获取具体的错误信息。
常见的错误码包括EACCES权限不足、EADDRINUSE地址已经被占用、EAFNOSUPPORT地址族不支持、EINVAL参数无效、EMFILE达到进程允许打开的最大文件数目、ENFILE系统打开文件数目过多、ENOBUFS/ENOMEM内存不足、EPROTONOSUPPORT协议不支持等。
bind函数在网络编程中扮演着至关重要的角色它主要用于将一个本地协议地址包括IP地址和端口号赋予一个套接字。
以下是关于bind函数的详细解释
①sockfd这是由socket()函数返回的文件描述符代表已经创建的套接字。
sockaddr_un它包含了地址、端口和可能的IP地址信息。
③addrlen这是地址结构的长度通常以字节为单位。
对于IPv4通常使用sizeof(struct
sockaddr_in)对于IPv6使用sizeof(struct
sockaddr_in6)对于Unix域套接字使用sizeof(struct
如果bind函数成功执行它返回0。
如果出现错误返回-1并设置全局变量errno以指示错误原因。
常见的错误包括EACCES权限不足、EADDRINUSE地址已经被使用、EADDRNOTAVAIL地址不可用、EAFNOSUPPORT地址族不支持该套接字类型、EINVAL套接字未打开、ENOTSOCK文件描述符不是套接字等。
在TCP服务器程序中bind函数通常用于指定服务器应监听的端口号。
服务器在启动时捆绑其众所周知的端口以便客户端可以连接到它。
在Unix域套接字中bind函数可以用来指定套接字在文件系统中的路径名。
在调用bind函数之前套接字必须处于未连接状态对于面向连接的套接字如TCP。
如果addr参数中的地址或端口号为0系统将为套接字自动选择一个可用的地址或端口号。
在多线程环境中应确保对bind函数的调用是线程安全的避免竞态条件。
绑定的本质将用户态的sockaddr_in设置进内核变为系统态。
对于端口号而言如果用户没有调用bind函数进行显式绑定那么系统在第一次发送消息时会随机给套接字绑定一个端口号。
recvfrom函数是一个在POSIX兼容操作系统如Linux中用于接收数据的系统调用。
它主要用于从指定的套接字接收数据并适用于面向无连接的协议如UDP用户数据报协议。
②buf创建好的一块缓冲区的地址。
用来承接从网络中读取到的数据。
⑤src_addr输出型参数该结构体里面包含着数据发送方的信息如port、ip等等。
如果不需要这些信息可以设为null。
成功时返回接收到的字符数字节数。
如果没有可用数据或者连接已经关闭返回0。
如果出现错误返回-1并设置errno错误号。
此时可以通过perror()函数来打印出错误信息。
在调用recvfrom函数之前需要先使用bind函数将socket绑定到一个地址上。
如果套接字是非阻塞的recvfrom函数可能会在没有接收到任何数据时返回-1并设置errno为EAGAIN或EWOULDBLOCK。
如果接收到的数据比缓冲区还大那么只会取缓冲区大小的数据并将剩余的数据丢弃。
sendto函数是一个系统调用用于将数据从指定的套接字发送到目标地址。
它通常用于UDP用户数据报协议通信因为UDP是无连接的所以sendto函数允许你向一个特定的地址发送数据报而不需要事先建立连接。
sockfd已经创建好的socket文件描述符。
buf指向要发送的数据的缓冲区。
len要发送的数据长度。
flags发送选项标志可以是0或者像MSG_DONTWAIT这样的选项。
MSG_DONTWAIT表示非阻塞发送如果发送缓冲区满则不等待直接返回。
dest_addr目标地址的sockaddr结构体指针。
对于IPv4这通常是一个指向struct
sockaddr_in的指针对于IPv6则是一个指向struct
sockaddr_in6的指针。
addrlen目标地址结构体的长度例如sizeof(struct
sendto函数的返回值是一个long类型的整数表示发送的字节数。
具体返回值有以下几种可能
如果返回值大于0则表示数据已经成功发送到了目标地址。
返回值代表实际发送的字节数。
如果返回值等于0表示发送的数据长度为0。
这可能是因为buf指向的空间长度为0或者在使用UDP协议时sendto函数成功地发送了0字节的数据。
如果返回值等于-1表示发送过程中出现了错误。
此时可以通过检查errno的值来确定具体的错误原因。
例如如果errno为EINTR表示sendto函数被一个信号中断了如果errno为EAGAIN或EWOULDBLOCK表示发送缓冲区已满无法立即发送数据这通常发生在使用了MSG_DONTWAIT标志的情况下。
需要注意的是sendto函数不保证数据的可靠传输。
也就是说发送的数据可能会丢失或者接收方可能无法按照发送的顺序接收数据。
如果需要可靠的数据传输应该使用TCP协议而不是UDP。
此外在使用sendto函数之前需要确保已经通过socket函数创建了一个套接字并且对于面向连接的套接字类型已经通过connect函数与目标地址建立了连接尽管对于UDP连接通常不是必需的但也可以通过connect建立默认的目标地址。
同时也需要确保目标地址是有效的并且发送的数据缓冲区是正确设置的。
udpServer{public:udpServer(const
sizeof(local));local.sin_family
你如果要给别人发消息你的port和ip要不要发送给对方local.sin_addr.s_addr
inet_addr//local.sin_addr.s_addr
我们只把数据读上来就完了吗对数据做处理_callback(clientip,
message);}}}~udpServer(){}private:uint16_t
服务器一旦开始运行就不会停止。
所以服务器本质就是一个死循环。
这种一直运行的进程叫做常驻进程。
一般来说服务器不会显式的绑定某一个ip。
因为一个主机可能会有不同的ip。
但是这台主机内的端口号是唯一的客户端都是发送信息到特定的端口号上。
所以服务器为了可以接收到所有发到这台主机上的信息(不会存在数据丢弃的情况选择绑定0.0.0.0作为自己的ip。
这样就可以接受到任何发送到这台主机指定端口的所有信息。
udpClient{public:udpClient(const
client要不要bind[必须要的]client要不要显示的bind需不需程序员自己bind不需要//
*(args));pthread_detach(pthread_self());while
sizeof(server));server.sin_family
inet_addr(_serverip.c_str());server.sin_port
);fflush(stderr);fgets(cmdline,
stdin);cmdline[strlen(cmdline)-1]
sizeof(server));}}~udpClient(){}private:int
端口号是需要绑定端口号的但是不需要显式的绑定端口号的。
绑定端口号的工作交给操作系统自主完成这个工作由操作系统在客户端初次发送消息时完成。
相对于服务端来说客户端必须绑定特定的端口号但是端口号的数值对于客户端来说就显得不太重要。
服务端必须指定特定的端口号以供客户端根据该端口号来向服务端发送消息。
但是客户端而言如果显式指明端口号必然会出现两个客户端竞争一个端口号的情况。
所以在通信时就由操作系统随机分配一个端口号供客户端进行通信。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback