[转]编写基于TCP的应用程序

本文介绍了TCP编程中的关键原理和技巧,包括正确使用循环进行数据发送与接收的方法,以及如何处理报文边界问题。还讨论了标准IO接口的工作机制,并强调了字符串处理时的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自: http://www.ideawu.net/blog/?p=429

这似乎是一个非常简单的话题, 就跟"是个人就能做网站"一样, 你可能也认为"是个人就能写使用TCP socket的网络程序". 不过, 下面介绍的几个基本的原理的做法, 你可能并没有理解.

TCP是一种流式的协议, 简单的说, TCP不检查数据的语义, 更不会检查数据的边界. 而应用层一般使用的是报文协议. 为此, 产生了一些特定的用法和模式.

有几种方式可用来实现报文协议:

1. 明确声明报文数据的长度.
2. 使用分隔符.
3. 发送方发送完数据后关闭连接.

第3种是socket的特定用法.

很难被理解的常用的TCP应用程序惯用法:

1. 必须使用循环来发送数据

对于原始的socket, 发送数据的函数是write:

ssize_t write(int fd, const void *buf, size_t count);

但write可能只发送你请求的数据的前面一部分, 也就是说, write返回值(表示已发送的的字节数)可能小于参数中的count. 所以, 你应该在循环中调用 write, 并检查返回值. 请认真的看看 APUE(Advanced Programming in the UNIX)的相关内容.

2. 必须使用循环来接收数据

读取数据的接口函数:

ssize_t read(int fd, void *buf, size_t count);

我常常见到有些人, 因为没有完整地接收到的发送方发送的数据, 而报怨发送方调用了多次write方法. 这是一种错误的报怨, 基于对TCP的错误理解. *无论对方调用多少次write, 你都不能只调用一次read! 即使你把接收缓冲设置为1GB也不行!*

首先, 发送方调用write, 把数据拷贝到发送方的发送缓冲区, 然后发送方的网络子系统一段(fragment)一段地发送缓冲区中的数据. 接收方的网络子系统将这些数据片段按顺序组装到接收缓冲区中, 一旦进入接收缓冲, 就不存在片段的说法. 接收方调用read方法, 可能读取部分或者全部缓冲区中的数据后返回, 如果只是部分, 这部分的数据和分段没有任何联系 - 记住这一点!

3. 标准IO接口只调用一次fgets/fputs

标准IO的gets/puts向上提供了基于报文的接口, 它们检查缓冲区中数据的分隔符'/n', 以便分隔出报文. 所以, 当你只调用一次gets就能读取对方调用一次puts发送的数据时, 不要感到惊讶. 标准IO帮你封装了循环读和写.

4. 总是在字符串的结尾加上'/0'

如果你想把某一段字节数组当作C字符串来处理, 那么你必须手动地在字符串应该是'/0'的地方加上'/0'. 例如, 如果你认为ptr[0-5](共6个字节的数据, 最后一个字节的值应该是'/0')是一个字符串, 那么, 在进行处理之前, 应该执行ptr[5] = '/0'; 注意, 千万不要执行ptr[strlen(ptr)] = '/0'! 这样, 才能保证无论对方是无意或者恶意地没有包含'/0', 你都能安全地进行处理. 另外, 不必在接收前执行类似memset(ptr, 0, BUFLEN)的语句, 这样会浪费一丁点的性能, 只修改一个字节总比修改6个或者更多的字节速度更快.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值