处理套接字上的多个消息 [英] Handling multiple messages on a socket

查看:67
本文介绍了处理套接字上的多个消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


我正在编写一个服务器应用程序.客户端连接到它,并每秒发送一些信息请求,对此我做出了响应.这一切都很好.但是,如果我在代码中放置一个断点并将其暂停几秒钟,然后让它运行,则消息会堆积起来,以便服务器代码中对recv的下一次调用会用几个客户请求消息.这使我意识到,尽管到目前为止还没有引起任何问题,但我并没有考虑到这一点.

因此,我一直使用换行符来分隔消息并分别进行处理,而在我认为只有第一条消息被处理之前.

但是,我注意到在处理完所有堆积的消息之后,在下一次对recv的调用(由select()触发)上,recv缓冲区中似乎仍然有相同数量的消息.尽管收到的字节数似乎是正确的,但我已处理的所有消息似乎都没有清除.例如,如果每个消息为20字节,则暂停然后重新启动系统将导致立即接收4条消息,因此我收到80个字节.处理完这些后,接收到的下一条消息将为20个字节,并且recv()方法正确返回vlue20.但是,recv()填充的缓冲区中仍包含80个字节的消息.我尝试清除对recv的调用之间的缓冲区,这没有区别.

有什么想法我要去哪里吗?

我不确定代码是否会有所帮助,但是无论如何我都将其放在下面.

这是调用recv的代码的摘录:

Hi,
I am writing an application which is a server. A client connects to it and sends a request for some information every second, to which I respond. This all works fine. However, if I put a breakpoint in the code and pause it for a few seconds, and then let it run, the messages pile up so that the next call to recv in my server''s code fills the recv buffer with several of the clients requests for messages. This alerted me to the fact that I had not catered for this even though it hadn''t caused any problems so far.

So, I have been using the newline character to seperate the messages and process them individually whereas before I think only the first message was processed.

However, I have noticed that after I have processed all the messages that are stacked up, on the next call to recv (which is triggered by select()) the recv buffer still seems to have the same number of messages in it. All the messages that i have processed do not seem to be cleared, although the number of bytes received seems to be correct. For example, if each message is 20 bytes, pausing then restarting the system causes 4 messages to be received at once so that I receive 80 bytes. Once these are processed, the next message received will be 20 bytes, and the recv() method correctly returns a vlue of 20. However, the buffer filled by recv() still contains 80 bytes worth of messages in it. I have tried clearing the buffer in between calls to recv, and this makes no difference.

Any ideas where I am going wrong?

I am not sure that the code will help but I''ve put it below anyway.

This is the extract of code which calls recv:

char recvBuf[BUFLEN];
int recvBufLen = BUFLEN;//512

FD_ZERO(&rxSet);
FD_SET(m_clientSocket, &rxSet);
maxFD = m_clientSocket;//jl - not needed, just for comaptibility with linux version

sockVal = select(maxFD, &rxSet, NULL, NULL, &timeOutVal);
			
if(sockVal > 0)
{
	if(FD_ISSET(m_clientSocket, &rxSet))
	{
	     int bytesReceived = recv(m_clientSocket, recvBuf, recvBufLen, 0);
	     if(bytesReceived > 0)
             {	
		RespondToAllMessagesFromController(recvBuf);
	     }
        }//if(FD_ISSET)
}



这是我分离消息并对其进行处理的地方



And this is where I seperate the messages and process them

int ClientHandlerThread::RespondToAllMessagesFromController(char* recvBuf)
{
	//The recvBuf may contain several messages that have been received on the client socket. The messages
	//will be separated by a newline character ''\n''. This method seperates the data in the buffer into
	//separate messages and processes each one seperately.

	int numMsgs = 0;//number of messages received in recvBuf
	int positionOfNewLine = 0;//index of newline character on recvBuf
	char responseMsgToController[200];//was [100]
	int startPosition = 0;

	//find the address of the first newline character in recvBuf
	char* pNewLineAddress = strchr(recvBuf, ''\n'');

	while(pNewLineAddress != NULL)
	{
		numMsgs++;//jl - rmv

		positionOfNewLine = (int)(pNewLineAddress - recvBuf);
		//convert recvBbuf to a string
		string recvString(recvBuf);
		string singleMsgString = recvString.substr(startPosition, (positionOfNewLine + 1) - startPosition);
		
		//convert singleMsgString to char*
		char* singleMsgBuf = (char*)(singleMsgString.c_str());
		startPosition = positionOfNewLine + 1;
		
		//now process this message
		ProcessClientMessage(singleMsgBuf, responseMsgToController);

		pNewLineAddress = strchr(recvBuf + startPosition, ''\n'');
	}

	//if responseMsgToController is not empty
	if(strcmp(responseMsgToController, "") != 0)
	{
		int bytesSent = send(m_clientSocket, responseMsgToController, static_cast<int>(strlen(responseMsgToController)), 0);
		ATLTRACE("msg sent: %s\n", responseMsgToController);
		ATLTRACE("bytes sent: %i\n", static_cast<int>(strlen(responseMsgToController)));
	}
	return 1;
}

推荐答案

好吧,我不确定规则到底是什么,但我认为您不应该查看超出范围的数据. 计数"说在那里.

哦,从理智上看,除了recv()告诉您的内容之外,还可以查看缓冲区的内容,这很有趣,但是我认为浪费时间来弄清楚为什么它不是您所期望的.有人告诉您只有20个字节有效.谁真正在乎无效字节的值是什么"?

另请注意,"recv()"不会在接收缓冲区中插入空字符",因此依赖于运行为null的任何代码都可能会出现问题.

最后,您遇到了网络/TCP/IP编程的基本基础技术,即您(应用程序)无法完全控制缓冲.

您可以控制"send()"字符数.您还可以控制"recv()"缓冲区的大小.但是,网络中的所有其他内容都具有中间缓冲区大小,从以太网帧到系统间路由层缓冲区.任何这些都可能缩短"或汇总多个"缓冲区(如您所发现的).

也不能保证您的"recv()"将包含整个消息,也就是说,接收到的字符可能只是消息的第一部分,其余字符可以由后续的"recv()"看到.由于您依靠"\ n"的外观来完成消息框架"(即确定一条消息的末尾,因此确定下一条消息的末尾),因此您的
Well, I''m not sure exactly what the rules are but I don''t think you should be looking at the data beyond what the "count" says is there.

Oh, intellectually it''s interesting to look at the contents of the buffer beyond what the recv() told you was valid but I think it''s a waste of time trying to figure out why it''s not what you expect. You were told that only 20 bytes were valid. Who really cares what the ''value of invalid bytes are''?

Also note that "recv()" isn''t going to stick a "null character" into your receive buffer so any code you have that relies on running into the null might have problems.

Finally, you have run into a basic underlying technique of network / TCP/IP programming, that you, the application, are not in complete control about buffering.

You control the "send()" character count. You also control the "recv()" buffer size. However, everything else in the network owns the intermediate buffer sizes, from ethernet frames to intersystem routing layer buffers. Any of those could "shorten" or "roll up multiple" of your buffers (as you discovered).

There is also no guarantee that a "recv()" by you will contain the entire messsage, that is, the received characters may only be the first part of the messsage, the remainder can be seen by a subsequent "recv()". Since you are relying on the appearance of "\n" to accomplish "message framing" (i.e. detencting the end of one message and hence the beginning of the next message), it is possible that your
strchr(recvBuf, ''\n'');

语句可能找不到'在位置0到(BytesReceived-1)之间的"recvBuf"范围内的'\ n'.

对于小"消息或大小一致的消息,您可能看不到此消息,但是当网络繁忙或服务器的cpu忙于其他事情时,您至少会遇到消息传递缓冲现象,并且可能最终导致出现跨muliple recv()'s的消息"问题.

statement will not find the ''\n'' in the confines of ''recvBuf'' between positions 0 thru (BytesReceived - 1).

With "small" messages, or messages of uniform size, you may not see this but when the net is busy, or the server''s cpu is busy with other things, you will at least experience the buffering of messasge effect and that may eventually lead to the "message spanning muliple recv()''s" problem.


这篇关于处理套接字上的多个消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆