recvfrom() not getting everything - c++

I'm having some issues with recvfrom() not getting all the packets in C++. (and then blocking and not returning)
I send 1 query packet, and then a response is sent.
It's broken into multiple packets of 805 bytes and then ended with a packet of ~200 bytes.
From my tests, 54 packets are received in total.
However, my program is only receiving 25-35 packets total, and not the ending packet, although the packets seem to be arriving fine in WireShark.
My code can be seen here:
sockaddr_in local, dest;
local.sin_family = AF_INET;
local.sin_port = htons(58770);
local.sin_addr.S_un.S_addr = INADDR_ANY;
dest.sin_family = AF_INET;
dest.sin_addr.S_un.S_addr = inet_addr(QUERYADDR);
dest.sin_port = htons(20810);
SOCKET s;
if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
errex("socket() failed");
if(bind(s, (sockaddr*)&local, sizeof(local)) == -1)
errex("bind() failed!");
sendto(s, (const char*)QUERY, sizeof(QUERY), 0, (sockaddr*)&dest, sizeof(dest));
while(true)
{
sockaddr_in tsaddr;
char buf[8192];
int slcl = sizeof(tsaddr);
int res = recvfrom(s, buf, sizeof(buf), 0, (sockaddr*)&tsaddr, &slcl);
printf("%i\n", res);
}
closesocket(s);
WSACleanup();
Can anyone see anything wrong?

The most likely explanation is that the packets are being dropped somewhere along the line. Wireshark just tells you that the packets are on the wire, not that they are being correctly received by the receiver.
Try checking your SO_RCVBUF socket option on the receiver to make sure that's not being overrun (which will result in dropped packets), as well as checking your network driver for any indications of errors or other problems.

In my case, it's MFC project that has console window (AllocConsole). After commented out that one, started receiving almost all of packets sent from server
(I've read that standard file IO takes too much time to write and read to console window, so my guess is while it's busy to print texts, missing to recv packets)

Related

C++ socket stuck sending data

I'm trying to develop a streaming system sending multiple images to a receiving socket, which displays them. However, for some reason I can't understand, my code gets blocked at the send function after sending about 3 images. This is a snippet of my code so far:
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
bzero(buffer,256);
for(int i=10;i<51;i++){
std::stringstream sstm;
sstm << filename << i << ext;
result = sstm.str();
cout << result << endl;
Mat image = imread(result, CV_LOAD_IMAGE_COLOR);
image = (image.reshape(0,1));
int imgSize = image.total()*image.elemSize();
n = send(sockfd, image.data, imgSize, 0);
}
Tried to debug it, and, as I said, it gets blocket at the last line, the send function. I wonder if there's a limit on how much information can you transmit through a socket. If I move the for sentence back before the socket creation, it works like a charm, but i'm not going to create a bizillion sockets. Any help?
The send() call will block if the TCP window size goes to zero. This is almost always a result of the other side of the connection not consuming the data from a recv() call.
It's also entirely possible that imgSize is extremely huge and it just simply takes that long for the receiver to consume the stream.
You didn't share any code from the receiver side, so it's difficult to say.
I would suggest more debug spew (print statements) showing the value of imgSize and the return value of the send call. Ditto for the recv side.
Do note - that just because you sent imgSize bytes in one send call, the remote receiver may not receiver all those bytes within a single call to recv().

C++: Linux: TCP/IP program crashes when calling write()

I have a loop which keeps writing data to a client through TCP/IP. The connection is opened as follows:
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
The following line is executed continuously in a loop (with sleep of 0.1 sec) in order to write the data to the client:
n = write(newsockfd,data.c_str(),data.length()+1); //+1 to include NULL in null terminated string
if(n>=0)
{
cout<<"success"<<endl;
}
else
{
cout<<"Fail"<<endl;
close(newsockfd);
newsockfd = -1;
}
I want the server to become reading for receiving a new connections if the connection is broken for any reason. So if writing fails, I get ready again to accept a new connection with the first command.
My problem is the following: the method succeeds for the first time, so if the connection is broken from the client, write() returns a negative number and I know immediately that the connection has a problem, so I close it and expect a new one. The server receives the new connection, but at the next time when using write(), the program crashes immediately.
Why does this happen? Please help, I'm new in TCP/IP stuff.
Please ask for more information if you require it.
Requested from helpers:
Stack trace:
Error: signal 13:
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x402155]
/lib/x86_64-linux-gnu/libc.so.6(+0x364a0)[0x7ffc57ac04a0]
/lib/x86_64-linux-gnu/libpthread.so.0(write+0x10)[0x7ffc5836dcb0]
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x4023b6]
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x401b54]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7ffc57aab76d]
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x402081]
Variable definitions: it's a class:
Body:
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
Constructor starts the stuff:
LinuxTCPServer::LinuxTCPServer(int port, bool nonblocking)
{
if(nonblocking)
sockfd = socket(AF_INET, SOCK_NONBLOCK | SOCK_STREAM, 0);
else
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = port;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
}
Assuming Linux >= 2.2, replace this:
n = write(newsockfd,data.c_str(),data.length()+1);
with this:
n = send(newsockfd, data.c_str(), data.length()+1, MSG_NOSIGNAL);
send(2) will then return -1 with errno set to EPIPE, rather than generating a fatal SIGPIPE. Alternatively, ignore SIGPIPE.
When you receive the SIGPIPE, the connection behind newsockfd has been broken. We don't have enough code to reproduce the problem, client and server, so it's rather moot to say what might actually be wrong. However, converting SIGPIPEs to EPIPEs will at least give your server a chance to handle the broken connection.
Your stack trace indicates that the program is crashing with signal 13, which means you have a broken pipe.
That would indicate that your connection is broken, but you are still trying to write to it. See this thread for why that might causes the broken pipe error: What causes the Broken Pipe Error?
Now, on how to solve the issue, I suspect you're not actually getting a proper connection setup on your 'accept' call. Make sure you check the status of your 'accept' call before calling write.
The problems that are causing your accept call to fail are likely on the other side of the connection I think.

UDP server connecting and sending data weirdness

I am making async (well non-blocking rly) sockets lib for educational purposes. TCP part works just fine, but when it comes to UDP i experience weird behavior. Following code works as expected - server receives data:
MyUDPSocket server;
server.Bind(5551);
MyUDPSocket client;
client.Connect("192.168.0.103", 5551);
Sleep(10);
client.Write("\x0", 1);
Sleep(10);
client.Write("test", 5);
But if either of Sleep() or client.Write("\x0", 1); are commented out - it stops working. Server just would not get data. Here are some parts of my library to give you clue how exactly sockets are made:
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
...............................................
memset( &name, 0, sizeof(name) );
name.sin_family = AF_INET;
name.sin_port = htons( port );
hostent* hostinfo = gethostbyname( address );
name.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
connect(s, (sockaddr*)&name, sizeof name)
Nothing fancy as you see. Maybe it is some unspoken rule that sending one byte of data to initialize connection is required or something? I am really confused here.
Edit:
Write function as requested. name variable is very same that is set in Connect call whose code is above.
virtual int Write( void* data, int size )
{
return sendto(s, (const char*)data, size, 0, (sockaddr*)&name, sizeof name);
}
Edit:
Also in select() loop i check only for sockets being readable. Could it be case that socket is not writable due to connection being initialized? If that is the case it should solve First sleep. But what about sending one byte then?

WSARecvFrom on unconnected UDP socket does not return

I am writing a small program that tests an UDP network service. The implementation of the service is allowed to create a new socket for the session and respond to the client from there, at which point the client is then required to talk to this address (similar to TFTP).
Minimal client sans error checking looks like this:
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in destaddr = { ... };
MSGBUF msg[] = { ... };
DWORD sent;
WSASendTo(fd, msg, sizeof msg / sizeof *msg, &sent, 0, (sockaddr *)sa, sizeof sa, 0, 0);
char buffer[4096];
MSGBUF rcvmsg = { sizeof buffer, buffer };
DWORD received;
sockaddr_storage sa;
socklen_t sa_len = sizeof sa;
DWORD flags = 0;
WSARecvFrom(fd, &rcvmsg, 1, &received, &flags, (sockaddr *)&sa, &sa_len, 0, 0);
The client works fine if the server responds from the same address and port that the initial message was sent to, however replies from another port are silently discarded and the client hangs in WSARecvFrom.
Explicitly binding the socket to { AF_INET, INADDR_ANY, 0 } to force assignment of a local port, or invoking listen(fd, 5); makes no difference, as expected.
Is there anything in WSASendTo that implicitly connects an UDP socket, and if so, what should I do to avoid this?
UDP doesn't have connections. Datagrams are sent to and from ports; it's one-way communication.
It sounds to me like your server is letting itself be assigned a temporary port (i.e. passing 0 as the port in sockaddr_in), instead of using a specific port. This won't work.
Since UDP has no concept of a connection, each time you send data, it could be sent from a different port; the first send doesn't reserve the port that it was given, it just sends a datagram from it and then lets it go.
Your server should be binding itself to a specific port.
Meh, it was a firewall issue. Adding the application to the list of programs allowed to receive incoming traffic fixed the issue.

Reopen connected datagram socket

I have a connection protocol that has been defined by our customer. Data are sent between two linux computers using UDP and TCP protocols. The IP addresses and ports are fixed on startup.
We are sending messages at 200 Hz and I have been using connect to save some time on the transmissions.
My problem is that if there is a communication error, I need to tear down the connections and reinitialise.
I have a problem with one of the UDP connections as it will not rebind to the required address and returns errno 22.
The code I am using is something like:
int
doConnect(int& sock, int local_port, char *local_ip, int remote_port, char *remote_ip)
{
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(sockaddr_in);
addr.sin_family = AF_INET;
addr.sin_port = htons(local_port);
inet_pton(local_ip,&addr.sin_addr.s_addr);
if (0 > bind(sock, (struct sockaddr*)&addr, sizeof(addr)))
{
printf("Bind Error errno = %d\n", errno);
return ERR_BIND;
}
memset(&addr, 0, sizeof(sockaddr_in);
addr.sin_family = AF_INET;
addr.sin_port = htons(remote_port);
inet_pton(remote_ip,&addr.sin_addr.s_addr);
if (0 > connect(sock, (struct sockaddr*)&addr, sizeof(addr)))
{
printf("Connect Error errno = %d\n", errno);
return ERR_CONNECT;
}
return ERR_OK;
}
The way that this is used is like this:
int s1(-1), s2(-1);
doConnect(s1, 31003, "172.17.21.255", 31006, "172.17.21.1");
doConnect(s2, 31001, "172.17.21.3", 31004, "172.17.21.1");
When an error occurs
close(s1);
close(s2);
doConnect(s1, 31003, "172.17.21.255", 31006, "172.17.21.1");
doConnect(s2, 31001, "172.17.21.3", 31004, "172.17.21.1");
Here the local address is 172.17.21.3 and I am connecting to 172.17.21.1. s1 listens to a broadcast message.
s1 successfully reconnects to the remote machine, but s2 fails with error 22 from the call to bind.
I have tried explicitly calling bind and connect to an AF_UNSPEC address immediately before I close the socket. This doesn't solve the problem.
Are there any options that I should be using?
Perhaps you could try:
int val = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
I also suggest you double check that you're not passing the same socket to the two consecutive doConnect() calls (as errno 22 = EINVAL, which in the case of bind() appears to mean that the socket is already bound to an address).
The underlying socket layer might hold the port & IP address still open, even after your call to close. Try some of the following:
do a sleep(10) (or more) between the close and the call to doConnect again
configure the sockets using setsockopt with the SO_LINGER set to off
This actually happens more commonly with TCP connections, but I see no reason UDP can't have this problem as well.