我这里有一个UDP服务器,它监听端口9001.我已经为接收数据缓冲区定义了最大块大小4096 .
我的问题是,当客户端发送大数据时,例如 . 20000字节,我只收到我定义的块大小 . 我有一个无限循环,将不断从客户端收到数据 .
这是我的代码:
void TdaServer::StartServer()
{
#ifdef LOGGING_ENABLED
LOG_MSG("WARNING: StartServer called");
#endif
struct sockaddr_in cli;
//int socketId;
socklen_t size;
socketId=socket(AF_INET, SOCK_DGRAM, 0);
if (socketId < 0)
{
#ifdef LOGGING_ENABLED
LOG_MSG("ERROR: failed to create socket!");
#endif
}
int length = sizeof(server);
bzero(&server,length);
server.sin_family =AF_INET;
server.sin_addr.s_addr =INADDR_ANY;
int port = atoi(Config::GetEnv("nfc_demo_port").c_str());
if(port==0)
port = 9001;
server.sin_port =htons(port);
if (bind(socketId,(struct sockaddr *)&server,length)<0)
{
#ifdef LOGGING_ENABLED
LOG_MSG("Error binding!");
#endif
}
size = sizeof(struct sockaddr_in);
thread_parm_t *parm=NULL;
parm = new thread_parm_t;
parm->socketId = socketId;
parm->client = cli;
parm->size = size;
#ifdef LOGGING_ENABLED
LOG_MSG("TDA server started, socket id: %i, port: %d", socketId, port);
#endif
pthread_attr_t attr;
pthread_t clientthread;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&clientthread, &attr, Receive, (void *)parm);
}
void *Receive(void *parm)
{
thread_parm_t *p = (thread_parm_t *)parm;
char buffer[MAX_CHUNK_SIZE+1]; //MAX_CHUNK_SIZE = 4096
string data="";
extern int errno;
while(true)
{
#ifdef LOGGING_ENABLED
LOG_MSG("-TdaServer waiting for data...");
#endif
int n = recvfrom(p->socketId,buffer,MAX_CHUNK_SIZE,0,
(struct sockaddr *)&p->client, &p->size); //wasn't able to receive large data ex. 20000 bytes
#ifdef LOGGING_ENABLED
LOG_MSG("-TdaServer received data size: %d", n);
#endif
if(n>0)
{
data = data.append(string(buffer).substr(0, n));
#ifdef LOGGING_ENABLED
LOG_MSG("-TdaServer [%s] n: %d < mcs: %d, %s", inet_ntoa(p->client.sin_addr), n, MAX_CHUNK_SIZE, (n<MAX_CHUNK_SIZE?"true":"false"));
#endif
if(n<MAX_CHUNK_SIZE)//received complete
{
#ifdef LOGGING_ENABLED
LOG_MSG("-TdaServer received data size: %d, complete!", n);
#endif
TcbMgrConnection::SendResponse(data.c_str());
data = "";
}
}
else if(n<0)
{
#ifdef LOGGING_ENABLED
LOG_MSG("TdaServer: Error reading from socket");
#endif
}
else
{
if(n==0)
{
#ifdef LOGGING_ENABLED
LOG_MSG("IPServer: client %d disconnected", p->socketId);
#endif
//break;
}
}
}
close(p->socketId);
return NULL;
}
这是用VB.NET编写的UDP客户端代码
Private Sub cmdSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSend.Click
Dim pRet As Integer
Try
GLOIP = IPAddress.Parse(txtIP.Text)
GLOINTPORT = txtPort.Text
udpClient.Connect(GLOIP, GLOINTPORT)
bytCommand = Encoding.ASCII.GetBytes(txtMessage.Text)
pRet = udpClient.Send(bytCommand, bytCommand.Length)
Console.WriteLine("No of bytes send " & pRet)
txtInfo.Text = "INFORMATION" & vbCrLf & "No of bytes send " & pRet
Catch ex As Exception
Console.WriteLine(ex.Message)
txtInfo.Text = txtInfo.Text & vbCrLf & ex.Message
End Try
End Sub
我做得对吗?请帮助..提前致谢
3 回答
我不建议发送大型UDP数据包 . UDP分组数据大小限制在大约1300字节(假设路由器的典型MTU为1500或更小),更大的东西被路由器分段然后组装回来 .
如果路由中的任何路由器不允许碎片,则将丢弃所有数据包 . 如果任何片段丢失,整个数据包将被丢弃,即使在许多情况下仍然可以使用其余数据 .
传输较大块的更好方法是将它们手动分割成~1250字节的片段,然后在接收器处将片段粘合在一起 . 请记住,其中一些可能会丢失或无序到达 .
这就是recvfrom()的工作原理
分配更大的缓冲区或更改客户端以发送更小的数据包
从UDP套接字 dequeues exactly one datagram 读取 . 如果给它一个小于缓冲区的缓冲区,则丢弃其余的数据报大小 . 进一步读取下一个数据报的返回数据 . UDP不会为您执行任何数据连接/拆分 .
最大数据报大小为64KB(UDP标头中的大小字段为16位),因此您可以一次发送多达这么多,但最常见的是
write()
/ IP fragmentation . 在接收端,您必须将接受缓冲区大小与您发送的最大大小相匹配 .