socket() returns 0 in C client server application
socket() returns -1 on error.
A return of 0 means socket() succeeded and gave you file descriptor 0. I suspect that one of the file descriptors that you close has file descriptor 0 and once it's closed the next call to a function that allocated a file descriptor will return fd 0 as it's available.
accept returns 0 for 2nd, 3rd, etc client
Problem solved! I was accidentally closing fd 0 in my code, which caused this weird behaviour. Now everything works. Thanks for helping - you've showed me the right way
C TCP sockets, can 'send' return 0 after using select?
Zero is never possible. It will either transfer at least one byte and return the cost, or return -1 with errno == EAGAIN/EWOULDBLOCK
if the buffer is full in non-blocking mode, or -1 with some other errno
if there is a bad error. It shouldn't give -1/EAGAIN/EWOULDBLOCK
if select()
has indicated otherwise, except in the presence of multithreaded writing to the socket.
why write() doesn't return 0 when it should?
The only way to make write
return zero on a socket is to ask it to write zero bytes. If there's an error on the socket you will always get -1
.
If you want to get a "connection closed" indicator, you need to use read
which will return 0
for a remotely closed connection.
Socket read() function sometimes never returns 0 when processing tunneling
Your tunnel()
loop is completely ignoring the return values of read()
and write()
. Try something more like this instead:
bool writeAll(int sckt, void *buffer, size_t buflen)
{
char *pbuffer = (char*) buffer;
while (buflen > 0)
{
ssize_t numSent = write(sckt, pbuffer, buflen);
if (numSent < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
continue;
return false;
}
pbuffer += numSent;
buflen -= numSent;
}
return true;
}
...
strcpy(buffer, "HTTP/1.0 200 Connection established\r\n\r\n");
if (writeAll(client, buffer, strlen(buffer)))
tunnel(server, client, buffer);
close(client);
close(server);
return;
...
void tunnel(int server, int client, char *buffer)
{
int maxFD = max(server, client) + 1;
ssize_t numRead;
FD_SET fd;
int x = fcntl(server, F_GETFL, 0);
fcntl(server, F_SETFL, x | O_NONBLOCK);
x = fcntl(client, F_GETFL, 0);
fcntl(client, F_SETFL, x | O_NONBLOCK);
do
{
cout << "test" << endl;
FD_ZERO(&fd);
FD_SET(&fd, server);
FD_SET(&fd, client);
x = select(maxFD, &fd, NULL, NULL, NULL);
if (x < 0) break;
if (FD_ISSET(&fd, client))
{
numRead = read(client, buffer, BUFSIZE);
if (numRead <= 0) break;
if (!writeAll(server, buffer, numRead))
break;
}
if (FD_ISSET(&fd, server))
{
numRead = read(server, buffer, BUFSIZE);
if (numRead <= 0) break;
if (!writeAll(client, buffer, numRead))
break;
}
}
while (true);
}
As for why your reads are not always returning 0 when you are expecting, that is most likely due to the client and server using an HTTP keep-alive to keep the tunnel connection open after the server has sent its response, so the client can send subsequent requests to the same server using the same TCP connection. Establishing a new TCP connection, and even a new HTTPS session, on every HTTP/S request is time-consuming and wastes bandwidth as it involves many round trips for the TCP and TLS handshakes. So the default behavior of HTTP 1.1 and later is to keep a connection open unless either party explicitly states a close is wanted via a Connection: close
header.
Read system call returning zero bytes though the socket is ready for read
Without any code, it's hard to guess what exactly happens, but select()
succeeding does not necessarily mean that some data are ready to be read.
select()
just makes the promise that if you try one read from this file-descriptor you will not be blocked.
The reason might be any of these:
- the kernel stores in an internal buffer some data to be delivered through the file-descriptor you read (it's what you are expecting here),
- or the other end of the file-descriptor is closed, then no new data will ever be delivered (the EOF you observe),
- or the file-descriptor is in an invalid state for a read operation and any read attempt will immediately fail (see
errno
after read).
Related Topics
Which Is The Correct Way to Register a New Net_Device
Gunicorn Does Not Start After Boot
Do Here-Strings Undergo Word-Splitting
Linux Directory Starting with Dot
Python3 No Such File or Directory
Difference Between Archiving and Compression
List Files That Are in Directory1 But Not in Directory2 and Vice Versa
How to Get CPU Serial Under Linux Without Root Permissions
Detecting If The Monitor Is Powered Off
Why Does 'Ping' Not Timeout in Linux
How to Run Sh File from Another Sh File
How to Use 9-Bit Serial Communication in Linux
How to Install G++ on Centos Without Root
Kill Bash Script Foreground Children When a Signal Comes
Mmap Flag Map_Uninitialized Not Defined
Hbase Does Not Run After ./Start-Hbase.Sh - Permission Denied