使用套接字时如何考虑消息被分解?
How do I account for messages being broken up when using sockets?
我的设计
我正在使用套接字来实现聊天服务器。
客户端使用Java的java.net.Socket and BufferedReader从服务器读取消息。
服务器端使用Php的socket_read()从客户端获取消息。
它使用 Php 的 socket_write() 从服务器发送消息。 socket_write() 不保证会写出整个原始消息,这意味着我可能需要多次调用它才能发送出整个原始消息。
(在设计方面,客户端向服务器发送消息,服务器将这些消息重新路由到适当的客户端。)
担忧
我担心的是一条消息可能会被分解成几条较小的消息。因此,当服务器或客户端读取传入消息时,它实际上可能是原始消息的片段。
问题
这是我需要考虑的事情吗?
如果是,如何?
可能的解决方案
现在我正在考虑使用字节填充(这是一种网络技术,可以将字节插入到原始消息中,作为标志,在发送消息之前标记消息的开始和结束)。
如果您需要应用程序级别的消息,那么您必须在应用程序级别实现它们。有几种常见的做法:
1) 使用固定长度的消息。
2) 在每条消息前加上长度。
3) 使用自然不会出现在您的邮件中的 'end of message' 标记。
4) 使用 'end of message' 标记,如果它出现在您的消息中则将其转义。
是的,这是您需要在协议中处理的事情。
这里最典型的两种方法是:
制定协议 line-oriented。用换行符终止每条消息,并且在看到换行符之前不要将一行视为完整。当然,这取决于消息中不会自然出现的换行符。
一些使用这种方法的协议包括 SMTP、IMAP 和 IRC。
在其header中包含消息的长度,以便您知道要读取多少数据。
使用这种方法的一些协议包括 HTTP(在 Content-Length
header 中)和 TLS,以及许多 low-level 协议,例如 IP。
如果您不确定采用哪种方法,第二种方法实施起来要容易得多,并且不会对您使用的数据施加任何限制。一个简单的实现可能只是将字节数存储为压缩整数,并且可能类似于以下伪代码:
send_data(dat):
send(length of dat as packed integer)
send(dat)
recv_data():
size = recv(size of packed integer)
return recv(buffer)
(此代码假定抽象 send()
和 recv()
方法将阻塞,直到发送或接收整个消息。当然,您的代码必须使此工作适当。)
我的设计
我正在使用套接字来实现聊天服务器。
客户端使用Java的java.net.Socket and BufferedReader从服务器读取消息。
服务器端使用Php的socket_read()从客户端获取消息。
它使用 Php 的 socket_write() 从服务器发送消息。 socket_write() 不保证会写出整个原始消息,这意味着我可能需要多次调用它才能发送出整个原始消息。
(在设计方面,客户端向服务器发送消息,服务器将这些消息重新路由到适当的客户端。)
担忧
我担心的是一条消息可能会被分解成几条较小的消息。因此,当服务器或客户端读取传入消息时,它实际上可能是原始消息的片段。
问题
这是我需要考虑的事情吗? 如果是,如何?
可能的解决方案
现在我正在考虑使用字节填充(这是一种网络技术,可以将字节插入到原始消息中,作为标志,在发送消息之前标记消息的开始和结束)。
如果您需要应用程序级别的消息,那么您必须在应用程序级别实现它们。有几种常见的做法:
1) 使用固定长度的消息。
2) 在每条消息前加上长度。
3) 使用自然不会出现在您的邮件中的 'end of message' 标记。
4) 使用 'end of message' 标记,如果它出现在您的消息中则将其转义。
是的,这是您需要在协议中处理的事情。
这里最典型的两种方法是:
制定协议 line-oriented。用换行符终止每条消息,并且在看到换行符之前不要将一行视为完整。当然,这取决于消息中不会自然出现的换行符。
一些使用这种方法的协议包括 SMTP、IMAP 和 IRC。
在其header中包含消息的长度,以便您知道要读取多少数据。
使用这种方法的一些协议包括 HTTP(在
Content-Length
header 中)和 TLS,以及许多 low-level 协议,例如 IP。
如果您不确定采用哪种方法,第二种方法实施起来要容易得多,并且不会对您使用的数据施加任何限制。一个简单的实现可能只是将字节数存储为压缩整数,并且可能类似于以下伪代码:
send_data(dat):
send(length of dat as packed integer)
send(dat)
recv_data():
size = recv(size of packed integer)
return recv(buffer)
(此代码假定抽象 send()
和 recv()
方法将阻塞,直到发送或接收整个消息。当然,您的代码必须使此工作适当。)