I wrote the code in order to handle receiving UDP packets. The packets are all same length(120 bytes), and about 1,000 packets are coming in every second. Simply, my code is like this.
int sock = -1;
int flag = 0;
int nRead = 0;
#define LOCAL_BUFF_SIZE (8192)
char buff[LOCAL_BUFF_SIZE];
struct sockaddr_in sockAddr;
memset((void *)&sockAddr, 0x00, sizeof(struct sockaddr_in));
if((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
/* Print error and terminate */
}
/* Make it non-blocking */
flag = fcntl( sock, F_GETFL, 0 );
fcntl( sock, F_SETFL, flag | O_NONBLOCK );
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(portNum);
sockAddr.sin_addr.s_addr = INADDR_ANY;
if(bind(sock, (struct sockaddr *)&sockAddr, sizeof (sockAddr)) < 0)
{
/* Print error and terminate */
}
while(...)
{
nRead = recv(sock, buff, LOCAL_BUFF_SIZE, 0);
if(nBytes > 0)
{
/* Process the data */
}
else
{
/* If it's error, handle error */
}
}
When I wrote this code, I expect that recv() function returns every bytes in the UDP socket buffer at that moment, but, it seems that it only returns one packet(120 byte) every time even though there are more bytes in the buffer. So now I encountered with packet loss. I know that there are many other ways to solve this problem, but, for now reading all existent bytes in the UDP buffer at once is the easiest way for me. So, is there any way to read all bytes in the UDP buffer at once?
Thanks in advance
UDP is a message oriented protocol, therefore, you are getting single message in one recv operation. You can possible use recvmmsg() system call to receive multiple messages in a single call.
Related
I have trouble reading RTP packets from a multicast socket which is opened using
the following function:
int
open_multicast_socket
(const char *group_address,
uint16_t port)
{
assert(group_address != NULL);
int
s;
if (-1 != (s = socket(
AF_INET, SOCK_DGRAM, 0
)))
{
int
reuse = 1;
if (-1 != setsockopt(
s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse
))
{
struct sockaddr_in
sock_addr;
bzero(&sock_addr, sizeof sock_addr);
if (1 == inet_pton(
AF_INET, group_address, &sock_addr.sin_addr
))
{
sock_addr.sin_family = AF_INET;
sock_addr.sin_port = htons(port);
if (0 == bind(
s, (struct sockaddr*)&sock_addr, sizeof sock_addr
))
{
struct ip_mreq
mreq = {
.imr_multiaddr.s_addr = inet_addr(group_address),
.imr_interface.s_addr = htonl(INADDR_ANY)
};
if (0 == setsockopt(
s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof mreq
))
{
//fcntl(s, F_SETFL, O_NONBLOCK);
return s;
} // setsockopt
else
{
perror("setsockopt");
close(s);
}
} // bind
else
{
perror("bind");
close(s);
}
} // inet_pton
else
{
perror("inet_pton");
close(s);
}
} // setsockopt
else
{
perror("setsockopt");
close(s);
}
} // socket
else
{
perror("socket");
}
return -1;
}
If I read RTP header plus payload in one read operation, I get the entire
packet. However, if I attempt to receive the RTP header first, then - a custom
header in the payload - the 2nd read always gets a next RTP header instead,
discarding all attached data. Because payload length may vary, the only way to
receive a whole packet, it seems, is to guess its max possible size.
I tried to get a number of available bytes before reading:
ioctl(sock, FIONREAD, &nbytes);
but it always returns 0.
Polling on the socket always fails, as if no data is available at all.
When non-blocking is enabled (i.e. fcntl(sock, F_SETFL, O_NONBLOCK);) - read
always fails (-1), so does recv(sock, buf, buf_len, MSG_DONTWAIT).
So is there a way to properly parse RTP packets via consequensive non-blocking
read calls?
Non-blocking is essential, because it should be possible to check whether a connection was lost and re-open the socket if necessary.
Unlike TCP which is a stream based protocol, UDP is a packet based protocol. This means that whenever you read from a UDP socket (multicast or not) you'll get exactly one UDP datagram. If your buffer isn't big enough to hold the entire datagram, the remaining data is essentially lost.
Make sure your buffer is big enough to hold a complete datagram. If your network supports jumbo frames end-to-end that means your buffer should be 9000 bytes, otherwise it should be 1500 bytes.
One should read the complete buffer from the socket and then parse them.
One can create a buffer of MTU size, read from the socket to this temp buffer and then parser the complete buffer and then take action.
One can use select() or poll() to check if the data is present in the socket. Read it when it is available.
I have a while(1) loop that uses recvfrom to get data that has been sent to a domain socket from another process (P2).
The while loop needs to do 2 things, firstly listen for incoming data from P2, and secondly run another function checkVoltage().
So it runs a little something like this:
while(true)
{
listenOnSocket() /*listens for 100 u seconds*/
checkVoltage();
}
My issue is this: the listenOnSocket() function uses the recvfrom function to check for an input from another process. It spends 100usecs listening, then times out and proceeds to run the checkVoltage() function. So it spends like 99% of the time in the listenOnSocket() function. My issue is that if P2 sends information to the socket during the checkVoltage() function, then it will result in an error, stating: sending datagram message: No such file or directory.
Is there a way to have this loop check for any data that has been sent to the socket previously? That way if P2 sends data during the checkVoltage() function, it will not result in an error.
Thanks.
EDIT:
So the listenOnSocket() function creates a socket with the name FireControl when I run P1 (the program that receives data from P2) the FireControl file vanishes for a split second then reappears. If P2 sends data to P1 during this short period, it results in the error mentioned up top.
So I guess this means I should separate the creation of the socket from the recvfrom function, because the short period where the new socket is created it does not exist - if that makes sense.
I'm a dope, I should've separated them in the first place!
EDIT2: Here is listenOnSocket():
command listenOnSocket(int timeout, float utimeout) /*Returns null payload when no input is detected*/
{
command payload;
int sock;
socklen_t* length;
struct sockaddr_un name;
char buf[1024];
struct timeval tv;
tv.tv_sec = timeout;
tv.tv_usec = utimeout;
/* Create socket from which to read. */
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sock < 0)
{
perror("opening datagram socket");
payload = nullPayload;
}
/* Create name. */
name.sun_family = AF_UNIX;
strcpy(name.sun_path, NAME);
unlink(name.sun_path);
/* Bind the UNIX domain address to the created socket */
if (bind(sock, (struct sockaddr *) &name, sizeof(struct sockaddr_un)))
{
perror("binding name to datagram socket\n");
payload = nullPayload;
}
/*Socket has been created at NAME*/
if (timeout != 0 || utimeout != 0)
{
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
}
else
{
tv.tv_sec = 0;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
}
/* Read from the socket */
if (recvfrom(sock, &payload, sizeof(command), 0, (struct sockaddr *)&name, &length) < 0) /*Less than zero results from a timeout*/
{
payload = nullPayload;
}
unlink(NAME);
return payload;
}
and here is the loop that calls it:
while (1)
{
buffer = getADCValue();
checkVoltage();
temp = listenOnSocket(0, 100); /*Look for a new command*/
doStuffWithTempIfItHasChanged();
}
}
I guess this means I should separate the creation of the socket from the recvfrom function, because the short period where the new socket is created it does not exist
That is correct. If you open and close the socket every time in your listenOnSocket() socket, (a) you will lose any datagrams that got queued that you didn't read, and (b) sends while the socket is closed will fail ... of course. Nothing for them to send to.
Once you've bound the socket, the datagrams will accumulate in a buffer and can be read later using recvfrom. That said, if the buffer overflows, messages may be discarded.
I am trying to understand why my function dosnt sending the all string (Its send only 53576 elements from 365568:
This is the function I am using in the client side:
#define DATASIZEBUFFER 4000// 365568
void DieWithError(char *errorMessage);/* Error handling function */
void TcpClient ( char *servIP , unsigned short echoServPort , Hash_t *HashData)//(int argc, char *argv[])
{
int sock; //Socket descriptor
struct sockaddr_in ServAddr; //Echo server address
int bytesRcvd, totalBytesRcvd; //Bytes read in single recv()
//and total bytes read
// Create a reliable, stream socket using TCP
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
DieWithError(" socket () failed") ;
// Construct the server address structure
memset(&ServAddr, 0, sizeof(ServAddr)); /* Zero out structure */
ServAddr.sin_family = AF_INET; /* Internet address family */
ServAddr.sin_addr.s_addr = inet_addr(servIP);/* Server IP address */
ServAddr.sin_port = htons(echoServPort); /* Server port */
// Establish the connection to the server
if (connect(sock, (struct sockaddr *) &ServAddr, sizeof(ServAddr)) < 0)
DieWithError(" connect () failed") ;
for (;;)
{
// Send the string to the server //
if (send(sock, HashData->array , HashData->elementNumber, 0) != HashData->elementNumber)
{
printf ("Bytes Nedded to recived: %ld\nAnd (DATASIZEBUFFER) is %d\n", HashData->elementNumber , DATASIZEBUFFER);
DieWithError("send() sent a different number of bytes than expected");
}
}
send() does not guarantee that it would send all the data.
From send man page:
On success, these calls return the number of bytes sent. On error,
-1 is returned, and errno is set appropriately.
You can write a loop around send() and invoke it multiple times until all data is sent (or, error is returned). It could be something like the following (please modify it based on your needs):
size_t
Send(int sockfd, const void *buf, size_t len, int flag) {
size_t sent_total = 0;
for (int sent_now = 0; sent_total != len; sent_total += sent_now) {
sent_now = send(sockfd, buf + sent_total, len - sent_total, flag);
if (sent_now == -1) break;
}
if (sent_total != len) {
LOG("send requested = %zu, sent = %zu", len, sent_total);
}
return sent_total;
}
Update to address #Myst's comments:
Although the question did not mention it explicitly, I assumed that the sockets used are blocking, since there are no fcntl call. With that in mind, the following from send() man page explains the situation:
When the message does not fit into the send buffer of the socket,
send() normally blocks, unless the socket has been placed in
nonblocking I/O mode.
In nonblocking mode it would fail with the
error EAGAIN or EWOULDBLOCK in this case. The select(2) call may be
used to determine when it is possible to send more data.
For non-blocking socket, the design need to be different and is outside the scope of this discussion.
My intent is to write a function which takes as parameter a buffer holding an entire ethernet frame and sends it to a raw socket (so needed only for transmission).
Here the obvious steps:
sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
// ...
write(sockfd, buffer, buffer_len);
// ...
close(sockfd);
But the write function fails with an EXNIO error code: "No such device or address". I grab the packet content from a wireshark session, so it should be well formatted.
There are several examples on internet about sending a raw eth packet, but I haven't found anything using write() instead of sendto(), which requires the sockaddr_ll struct to be filled.
Has anyone experienced the same issue? Is using sendto() the only way to accomplish the task?
Thanks.
Note: the program runs as root.
Here is a part of code which worked for me. In my understanding of things, write will not work as it is supposed to send a stream of chars. It can write to a file or to a TCP connection or similar. I think that raw packets are very different.
int sock;
sock = socket(PF_INET, SOCK_RAW, 0);
if (sock < 0) {
printf("Can't get socket\n");
exit(1);
}
/* Insist that we have header included */
int one = 1;
if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, &one, sizeof (one)) < 0) {
printf ("Cannot set IP_HDRINCL!\n");
exit(1);
}
...
struct sockaddr_in sockin;
sockin.sin_family = AF_INET;
sockin.sin_port = dest_port;
sockin.sin_addr.s_addr = dest_ip;
...
sendto (sock, buffer, bufferlen, 0, (struct sockaddr *) &sockin, sizeof (sockin));
...
close(sock);
it seems that when i use send() function (in a TCP file transfer program) like this
while((count = recv(socketConnection, buff, 100000, 0))>0)
myfile.write(buff,count);
the function recv() just waits untill the whole data comes and exits the loop when it is no more receiving any data but in a similar program for a UDP program
while((n = recvfrom(sockfd,mesg,1024,0,(struct sockaddr *)&cliaddr,&len))>0)
myfile.write(mesg,n);
the recvfrom() function just blocks and does not exit the loop for some reason, as far as i know both recv() and recvfrom() are blocking right?? Then why the difference. Does it have something to do with the functions or just the nature of TCP,UDP(which i guess is not a reason)??
P.S. Please help me understand this guys, I'm a newbie to socket programming and networking.
EDIT: full server program for both TCP and UDP
UDP server (with recvfrom() )
int i=0;
int sockfd,n;
struct sockaddr_in servaddr,cliaddr;
socklen_t len;
char mesg[1024];
sockfd=socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(32000);
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
ofstream myfile;
// fcntl(sockfd,F_SETFL,O_NONBLOCK);
myfile.open("2gb",ios::out);
while((n = recvfrom(sockfd,mesg,1024,0,(struct sockaddr *)&cliaddr,&len))>0)
myfile.write(mesg,n);
TCP (recv() ) server program
struct sockaddr_in socketInfo;
char sysHost[MAXHOSTNAME+1]; // Hostname of this computer we are running on
struct hostent *hPtr;
int socketHandle;
int portNumber = 8070;
//queue<char*> my_queue;
bzero(&socketInfo, sizeof(sockaddr_in)); // Clear structure memory
gethostname(sysHost, MAXHOSTNAME); // Get the name of this computer we are running on
if((hPtr = gethostbyname(sysHost)) == NULL)
{
cerr << "System hostname misconfigured." << endl;
exit(EXIT_FAILURE);
}
if((socketHandle = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
close(socketHandle);
exit(EXIT_FAILURE);
}
// std::cout<<"hi starting server";
socklen_t optlen;
int rcvbuff=262144;
optlen = sizeof(rcvbuff);
socketInfo.sin_family = AF_INET;
socketInfo.sin_addr.s_addr = htonl(INADDR_ANY);
socketInfo.sin_port = htons(portNumber); // Set port number
if( bind(socketHandle, (struct sockaddr *) &socketInfo, sizeof(socketInfo)) < 0)
{
close(socketHandle);
perror("bind");
exit(EXIT_FAILURE);
}
listen(socketHandle, 1);
int socketConnection;
if( (socketConnection = accept(socketHandle, NULL, NULL)) < 0)
{
exit(EXIT_FAILURE);
}
close(socketHandle);
time_start(boost::posix_time::microsec_clock::local_time());
int rc = 0; // Actual number of bytes read
int count=0;
char *buff;
int a=100000;
buff=new char[a];
ofstream myfile;
myfile.open("345kb.doc",ios::out|ios::app);
if(myfile.is_open())
{
long i=0;
while((count = recv(socketConnection, buff, 100000, 0))>0)
{
myfile.write(buff,count);
}}
the function recv() just waits untill the whole data comes and exits the loop when it is no more receiving any data
recv() on a TCP connection returns 0 when the sending side has closed the connection and this is the condition for your loop to terminate.
for a UDP program the recvfrom() function just blocks and does not exit the loop for some reason,
Because UDP is a connection-less protocol hence there is no special return code from recv() for a closed UDP connection. Unless someone sends you a 0-length datagram.
recv() will end the loop because at the other side the socket is closed, so recv() will return 0 (socket gracefully closed) whereas, recvfrom that does not have that signal, it does not know about closing, because it's an unconnected socket. It's stay there until it receives a packet or timeout, with UDP you need a way to tell that the communication is over (finish).