Reputation: 4231
I have here a UDP Server which listens on port 9001. I have defined a maximum chunk size of 4096 for receiving data buffer.
My problem is, when the client sends a large data, ex. 20000 bytes, I only received the chunk size I defined. I have an endless loop which will continuously received data from client.
Here is my code:
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;
}
Here is the UDP client code, written in VB.NET
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
Am I doing it right? Please help.. Thanks in advance
Upvotes: 0
Views: 1570
Reputation: 24429
I won't recommend sending large UDP packets. UDP packet data size is limited to about 1300 bytes (given that typical MTU of routers is 1500 or less), anything bigger is fragmented by router and then assembled back.
If any of the routers in the way does not allow fragments, all your packets will be discarded. If any fragment is lost, whole packet will be discarded, even though in many situations it's still possible to use the rest of the data.
A better way to transmit larger blocks, is to split them manually into pieces of ~1250 bytes, then glue pieces together at the receiver. Keep in mind that some of them can be lost or arrive out of order.
Upvotes: 1
Reputation: 84151
Reading from UDP socket dequeues exactly one datagram. If you give it a buffer smaller then the datagram size the rest is discarded. Further reading with return data from the next datagram. UDP doesn't do any concatenation/splitting of the data for you.
Maximum datagram size is 64KB (the size field in the UDP header is 16 bit), so you can send up to that much at a time with a singe write()
/send()
/sendto()
call, most likely resulting in IP fragmentation. On the receiving end you have to match the accepting buffer size to the maximum size you are sending.
Upvotes: 2
Reputation: 10119
That is how recvfrom() works
The recvfrom() function shall return the length of the message written to the buffer pointed to by the buffer argument. For message-based sockets, such as SOCK_RAW, SOCK_DGRAM, and SOCK_SEQPACKET, the entire message shall be read in a single operation. If a message is too long to fit in the supplied buffer, and MSG_PEEK is not set in the flags argument, the excess bytes shall be discarded. For stream-based sockets, such as SOCK_STREAM, message boundaries shall be ignored. In this case, data shall be returned to the user as soon as it becomes available, and no data shall be discarded.
Either allocate a larger buffer or change the client to send smaller packets
Upvotes: 2