2013-10-28 89 views
4

我有一个应用程序,其中各种实体通过套接字相互通信,我使用的是C编程语言。当一个实体向另一个实体发送一个长消息时,recv()函数可能会部分读取该消息。因此,我必须通过附加所有收到的部分来重新构造收件人一方的消​​息。套接字编程:recv()

我的问题是关于recv()的一般插座编程问题。 recv()如何知道消息何时被完全读取?我应该用一个特殊字符如“\ n”来终止邮件吗?或者我应该将邮件的大小作为标题发送?常用的做法是什么?

回答

6

正如您已经注意到的,使用流套接字没有内置的消息边界概念。您需要构建一些确定应用程序级协议中的消息结束的方式。

你提出的两个选项都是常见的:或者是一个长度前缀(用消息长度开始每个消息)或者是一个消息结束符(这可能只是一个基于文本的换行符协议,例如)。第三个较少使用的选项是为每条消息指定一个固定大小。这些选项的组合也是可能的 - 例如,包含长度值的固定大小头。

+0

谢谢......它真的有助于了解常见的做法。 – NewToAndroid

2

当您使用send()和recv()时,您指定一个缓冲区大小。

如果使用这样的方式来发送消息:

send(new_socket,message,strlen(message),0); 

第三个参数是你的缓冲区的大小。

学习成功发送数据包的一种方法是如果您使用的是TCP套接字,则send()recv()将返回相同的值。您可以通过检查邮件大小是否与从send()返回的值相同来检查发件人。

为了在接收端检查,最简单的方法是将字符串分隔符\0的末尾加到字符串中。

+0

为了发送分隔符,'strlen(message)+ 1'将会非常好。 – glglgl

+0

除此之外,最好谈谈“发件人方”。从连接开始,双方都可以发送和接收,所以使用术语“服务器”在这里是非常具有误导性的。 – glglgl

+0

@glglgl谢谢我将服务器和客户端固定到发件人和收件人。 此外,我认为字符串已经有\ 0分隔符,因此,这将已经包含在字符串的长度,但如果字符串没有分隔符,那么你是对的。 –

0

一旦开始在C语言中做大量的网络编程之一就很快实现为什么更高层次的语言流行起来!基本上他们有很多内置的功能,你很快就会发现自己希望C提供更多的功能!

首先我强烈建议你看看ZeroMQ(http://zeromq.org/bindings:c)及其C绑定。这在处理连接,消息分界等方面为你做了很多可怕的驴工作。另外,它在运行时很快;快速开发并快速运行,这是一个好的图书馆的标志。

ZeroMQ接近完美的套接字库。它唯一没有做的事情(AFAIK)主动监视连接,看看它是否崩溃 - 你只会发现是否尝试发送一些东西。如果您想检查连接的健康状况,则必须定期发送自己的连接测试消息。

其次,我会鼓励你考虑序列化。一旦你开始拥有指向分配内存的复杂数据结构,你将开始进入复杂而困难的领域。当面对这个问题时,我选择使用ASN.1来使用Objective Systems的库和工具(http://www.obj-sys.com/index.php)定义和序列化我的数据结构。它花钱,需要一点习惯,但我发现它在节省开发时间方面非常有价值。

以及序列化例程,他们给你一些非常方便的演员,C不提供。例如,他们的代码生成器将为您提供复制数据类型的例程,如果该数据类型是一个充满指向分配内存的指针的结构,那么它非常方便。

这里可能有一些免费的工具和库。 Google的协议缓冲区有一个C绑定(http://code.google.com/p/protobuf-c/),这是一个很好的选择。