There must be something wrong in the below code but I don't seem to be able to use a client connect, non blocking in combination with a select statement. Please ignore the below lack of error handling.
I seem to have two issues
1. select blocks until timeout (60) if I try to connect port 80 on an internet server
2. trying to connect a existing or non existing port on 127.0.0.1 always instantly returns the select with no way to distinction between success or failure to connect.
What am I missing in my understanding of BSD nonblocking in combination with select?
fd_set readfds;
FD_ZERO(&readfds);
struct timeval tv;
tv.tv_sec = 60;
tv.tv_usec = 0;
struct sockaddr_in dest;
int socketFD = socket(AF_INET, SOCK_STREAM, 0);
memset(&dest, 0, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
dest.sin_port = htons(9483);
long arg;
arg = fcntl(socketFD, F_GETFL, NULL);
arg |= O_NONBLOCK;
fcntl(socketFD, F_SETFL, arg);
if (connect(socketFD, (struct sockaddr *)&dest, sizeof(struct sockaddr))<0 && errno == EINPROGRESS) {
//now add it to the read set
FD_SET(socketFD, &readfds);
int res = select(socketFD+1, &readfds, NULL, NULL, &tv);
int error = errno;
if (res>0 && FD_ISSET(socketFD, &readfds)) {
NSLog(#"errno: %d", error); //Always 36
}
}
errno is set in your original attempt to connect -- legitimately: that is, it's in-progress. You then call select. Since select didn't fail, errno is not being reset. System calls only set errno on failure; they do not clear it on success.
The connect may have completed successfully. You aren't checking that though. You should add a call to getsockopt with SO_ERROR to determine whether it worked. This will return the error state on the socket.
One other important note. According to the manual page (https://www.freebsd.org/cgi/man.cgi?query=connect&sektion=2), you should be using the writefds to await completion of the connect. I don't know whether the readfds will correctly report the status.
[EINPROGRESS] The socket is non-blocking and the connection cannot
be completed immediately. It is possible to select(2)
for completion by selecting the socket for writing.
See also this very similar question. Using select() for non-blocking sockets to connect always returns 1
Related
If I set up a socket for non-blocking operation, as follows:
int fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
int rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
...is connect guaranteed to fail with EINPROGRESS, or do I need to handle the case where it succeeds immediately?
Not necessarily. Connecting to 127.0.0.1 may connect or fail immediately.
You need to handle the case where it succeeds immediately. That's why it returns 0 or -1. The documentation doesn't make any exception about that for non-blocking mode.
I have an application that sends a GET request using winsock on port 80 using a TCP socket. A few users have reported an issue where no response is received, looking at network logs and seeing the network device is getting the data just the app isn't it was clear that the firewall was blocking it.
Having disabled the firewall it then worked fine but what I don't understand is why it was getting blocked. The connection is created from the users computer, it connects fine and sends (which I assumes automatically opens a port) so how can data be lost on the same connection when received? Should I be providing additional winsock settings? Or is there simply no way around stopping the firewall blocking an already active connection?
Here is a stripped down version of the winsock code
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
return -1;
struct sockaddr_in client;
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(80);
client.sin_addr.s_addr = inet_addr(inet_ntoa(*addr_list[0]));
if (connect(sock, (struct sockaddr *)&client, sizeof(client)) < 0){
closesocket(sock);
return -1;
}
if (send(sock, buffer, buflength, 0) != buflength){
closesocket(sock);
return -1;
}
//get response
response = "";
int resp_leng = BUFFERSIZE;
while (resp_leng == BUFFERSIZE)
{
resp_leng = recv(sock, (char*)&buffer, BUFFERSIZE, 0);
if (resp_leng > 0)
response += std::string(buffer).substr(0, resp_leng);
else
return -1;
}
closesocket(sock);
Your while loop exits if a recv() returns less than BUFFERSIZE. This is wrong -- you must always assume that recv() can return any amount of data from 1 byte up to and including the supplied buffer size.
I've been writing a server and every time I quit it and re-open it, it seems to fail to bind to the socket. I'm connecting 2 clients and then disconnecting them with close() before I shut down the server, I also then quit the clients before opening the server just in case, however it still seems to fail and I have to restart my computer. Here is my code:
listenSocket = device = app = 0;
struct sockaddr_in server_addr;
char buffer[1024];
listenSocket = socket(AF_INET, SOCK_STREAM, 0);
memset(&server_addr, '0', sizeof(server_addr));
memset(buffer, '0', sizeof(buffer));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(35565);
//bind the socket
if (bind(listenSocket,(struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
NSLog(#"Error binding to socket");
}
if (listen(listenSocket, 5) == -1) {
NSLog(#"Failed to listen");
}
//launch thread for console
[NSThread detachNewThreadSelector:#selector(console) toTarget:self withObject:nil];
NSLog(#"Starting server");
//socket open, ask for clients
while (true) {
int client = -1;
if (!device || !app)
client = accept(listenSocket, (struct sockaddr*)NULL, NULL);
//handshake omitted for length
}
And the code to close the server:
close(listenSocket);
close(device);
close(app);
NSLog(#"Clean");
Is there something I'm doing wrong? Any help would be appreciated. Thanks.
EDIT: Here is my error checking code:
NSLog(#"%s",strerror(errno));
int e = bind(listenSocket,(struct sockaddr*)&server_addr, sizeof(server_addr));
NSLog(#"%s",strerror(errno));
You need to set the SO_REUSEADDR option. Otherwise, once you grab the port in a process, there is a significant timeout before the kernel will let you have it again. Much detail to be found in an existing question; I've voted to close as a duplicate.
I had a similar problem which was caused by another process holding on to the ports. Killing that process solved the problem.
I have multiple threads who have a socket open with a client application each. Each of those threads receive an instruction from a main thread to send commands to the client (commands could be run test, stop test, terminate session, exit....). Those threads are generic, they just have a socket per client and just send a command when the main thread asks it to.
The client could exit or crash, or network could be bad.
I have been trying to see how to figure out that my TCP session has ended per client. Two solutions that I have found that seem appropriate here.
1) Implement my own heartbeat system
2) Use keepAlive using setsockopt.
I have tried 2) as it sounds faster to implement, but I am not sure of one thing: Will SO_KEEPALIVE generate a SIGPIPE when connection is interrupted please? I saw that it should be the case but never received a SIGPIPE.
This is how my code looks:
void setKeepAlive(int sockfd) {
int optval;
optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
optval = 1;
setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, &optval, sizeof(optval));
optval = 1;
setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &optval, sizeof(optval));
optval = 1;
setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, &optval, sizeof(optval));
}
And my code that accepts connection is as follows:
for (mNumberConnectedClients = 0; mNumberConnectedClients < maxConnections; ++mNumberConnectedClients) {
clientSocket = accept(sockfd, (struct sockaddr *) &client_addr, &clientLength);
// set KeepAlive on socket
setKeepAlive(clientSocket);
pthread_create(&mThread_pool[mNumberConnectedClients], NULL, controlClient, (void*) &clientSocket);
}
signal(SIGPIPE, test);
....
And the test function:
void test(int n) {
printf("Socket broken: %d\n", n);
}
test() never gets triggered. Is it my understanding that is wrong please? I am not sure if SIGPIPE gets generated or not. Thanks a lot.
If a keep-alive fails, the connection will simply be invalidated by the OS, and any subsequent read/write operations on that socket will fail with an appropriate error code. You need to make sure your reading/writing code is handling errors so it can close the socket, if it is not already doing so.
I'm writing iPhone application which uses sockets and uses CFSocketConnectToAddress for creating sockets. I need to specify socket timeout in seconds. What is best timeout value in seconds for iPhone/iPod which uses wifi/3g/edge connection ?
Sample code:
#define SOCKET_TIMEOUT_VALUE ?
CFSocketRef sock_id = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketNoCallBack, NULL, NULL) ;
struct sockaddr_in addr4;
memset(&addr4, 0, sizeof(addr4));
addr4.sin_len = sizeof(addr4);
addr4.sin_family = PF_INET;
addr4.sin_port = htons([[hostValue port_number] intValue]);
inet_pton(AF_INET, inet_ntoa(*(struct in_addr *)host_name->h_addr_list[0]), &addr4.sin_addr);
CFDataRef addr = CFDataCreate(kCFAllocatorDefault, (void*)&addr4, sizeof(struct sockaddr_in));
int retVal = CFSocketConnectToAddress(sock_id, addr, SOCKET_TIMEOUT_VALUE);
if (retVal != 0)
{
// Failed to Connect!
errorNumber = FAILED_CONNECT ;
CFRelease(addr) ;
CFRelease(sock_id) ;
goto shutdown2;
}
Apple documentation for CFSocketConnectToAddress
EDIT:
App will have few socket creations same time for different hosts.
Thanks
Given typical circumstances, a socket will connect within an imperceptibly small amount of time (for the user). Sometimes that isn't the case. The structure of your application (specifically, the threading) should account for this.
The foremost rule is that you shouldn't block the main thread while waiting for the socket to connect. Show an indeterminate progress indicator that you're trying to connect. Give the user the ability to back up and choose not to proceed.
If you're looking for a numerical answer instead of a design answer, I frequently toss in sixty seconds.