This question already has answers here:
How to exit a blocking recv() call? [duplicate]
(2 answers)
Closed 7 years ago.
I want to exit a blocking recv() call. Based on this question, I should do the following:
shutdown(s, SD_RECEIVE);
But it is not working, recv() is still blocking!
Edit:
This is the code I used:
#include <stdio.h>
#include <WinSock2.h>
#include <Windows.h>
#include <process.h>
#pragma comment(lib, "ws2_32.lib")
unsigned int __stdcall recvThread(void *p)
{
SOCKET s = *((SOCKET*)p);
char buffer[2048];
int size;
do
{
size = recv(s, buffer, 2048, 0);
if (size > 0)
{
printf("Some data received\n");
}
else if (size == 0)
{
printf("Disconnected\n");
}
else
{
printf("Disconnected, error occured\n");
}
} while (size > 0);
return 0;
}
int main()
{
// Initialize Winsock
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
// Create socket
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
// Connect
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.1.4");
addr.sin_port = htons(atoi("12345"));
if (connect(s, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
printf("Unable to connect\n");
}
else
{
printf("Connected\n");
}
// Start recv() thread
HANDLE hRecvThread = (HANDLE)_beginthreadex(0, 0, recvThread, &s, 0, 0);
Sleep(3000);
// Exit blocking recv()
shutdown(s, SD_RECEIVE);
getchar();
return 0;
}
You need to shutdown the input as mentioned in the question you linked to.
See the documentation for shutdown() on msdn and here as well:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms738547%28v=vs.85%29.aspx
Relevant quote from the documentation:
The shutdown function is used on all types of sockets to disable reception, transmission, or both.
If the how parameter is SD_RECEIVE, subsequent calls to the recv function on the socket will be disallowed. This has no effect on the lower protocol layers. For TCP sockets, if there is still data queued on the socket waiting to be received, or data arrives subsequently, the connection is reset, since the data cannot be delivered to the user. For UDP sockets, incoming datagrams are accepted and queued. In no case will an ICMP error packet be generated.
If the how parameter is SD_SEND, subsequent calls to the send function are disallowed. For TCP sockets, a FIN will be sent after all data is sent and acknowledged by the receiver.
Setting how to SD_BOTH disables both sends and receives as described above.
The key is the FIN being sent. This will be handled by the server and it will close the socket, leading to your recv() call returning.
Related
This question already has an answer here:
Basic non blocking tcp connect example for C [closed]
(1 answer)
Closed 12 months ago.
I am trying to write a C code that connects using non-blocking TCP socket along with select(). When I read the man page about EINPROGRESS, I feel a little bit confused.
EINPROGRESS
The socket is nonblocking and the connection cannot be completed immediately. It is possible to
select(2) or poll(2) for completion by selecting the socket for writing. After select(2) indicates
writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine
whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one
of the usual error codes listed here, explaining the reason for the failure).
Is there any sample code I can refer to? Although it is a pretty old question, I don't see anyone post a complete working code. Some suggest to use connect twice but I don't know exactly how.
Sure, below is a little C program that uses a non-blocking TCP connect to connect to www.google.com's port 80, send it a nonsense string, and print out the response it gets back:
#include <stdio.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
static void SendNonsenseCommand(int sock)
{
const char sendString[] = "Hello Google! How are you!\r\n\r\n";
if (send(sock, sendString, sizeof(sendString), 0) != sizeof(sendString)) perror("send()");
}
int main(int argc, char ** argv)
{
// Create a TCP socket
const int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {perror("socket"); return 10;}
// Set the TCP socket to non-blocking mode
const int flags = fcntl(sock, F_GETFL, 0);
if (flags < 0) {perror("fcntl(F_GETFL)"); return 10;}
if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) {perror("fcntl(F_SETFL)"); return 10;}
// Get the IP address of www.google.com
struct hostent * he = gethostbyname("www.google.com");
if (he == NULL) {printf("Couldn't get a hostent for www.google.com\n"); return 10;}
// Start a non-blocking/asynchronous TCP connetion to port 80
struct sockaddr_in saAddr;
memset(&saAddr, 0, sizeof(saAddr));
saAddr.sin_family = AF_INET;
saAddr.sin_addr = *(struct in_addr*)he->h_addr;
saAddr.sin_port = htons(80);
const int connectResult = connect(sock, (const struct sockaddr *) &saAddr, sizeof(saAddr));
int isTCPConnectInProgress = ((connectResult == -1)&&(errno == EINPROGRESS));
if ((connectResult == 0)||(isTCPConnectInProgress))
{
if (isTCPConnectInProgress == 0) SendNonsenseCommand(sock);
// TCP connection is happening in the background; our event-loop calls select() to block until it is ready
while(1)
{
fd_set socketsToWatchForReadReady, socketsToWatchForWriteReady;
FD_ZERO(&socketsToWatchForReadReady);
FD_ZERO(&socketsToWatchForWriteReady);
// While connecting, we'll watch the socket for ready-for-write as that will tell us when the
// TCP connection process has completed. After it's connected, we'll watch it for ready-for-read
// to see what Google's web server has to say to us.
if (isTCPConnectInProgress) FD_SET(sock, &socketsToWatchForWriteReady);
else FD_SET(sock, &socketsToWatchForReadReady);
int maxFD = sock; // if we were watching multiple sockets, we'd compute this to be the max value of all of them
const int selectResult = select(maxFD+1, &socketsToWatchForReadReady, &socketsToWatchForWriteReady, NULL, NULL);
if (selectResult >= 0)
{
if ((FD_ISSET(sock, &socketsToWatchForWriteReady))&&(isTCPConnectInProgress))
{
printf("Socket is ready for write! Let's find out if the connection succeeded or not...\n");
struct sockaddr_in junk;
socklen_t length = sizeof(junk);
memset(&junk, 0, sizeof(junk));
if (getpeername(sock, (struct sockaddr *)&junk, &length) == 0)
{
printf("TCP Connection succeeded, socket is ready for use!\n");
isTCPConnectInProgress = 0;
SendNonsenseCommand(sock);
}
else
{
printf("TCP Connection failed!\n");
break;
}
}
if (FD_ISSET(sock, &socketsToWatchForReadReady))
{
char buf[512];
const int numBytesReceived = recv(sock, buf, sizeof(buf)-1, 0);
if (numBytesReceived > 0)
{
buf[numBytesReceived] = '\0'; // ensure NUL-termination before we call printf()
printf("recv() returned %i: [%s]\n", numBytesReceived, buf);
}
else if (numBytesReceived == 0)
{
printf("TCP Connection severed!\n");
break;
}
else perror("recv()");
}
}
else {perror("select()"); return 10;}
}
}
else perror("connect()");
close(sock); // just to be tidy
return 0;
}
I am learning about broadcasting in network programming (using C). From what I understand, a sender sends a message to all the receivers (who are listening) in the local area network. Using my local machine with a virtual machine I wrote a small program to see how things work.
Code for receiver.c (I put this code on my local machine):
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/unistd.h>
#define PORT 4242
int main() {
int socket_fd, sender_size;
struct sockaddr_in receiver, sender;
char receive_buff[256], send_buff[256];
socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (socket_fd < 0) {
perror("failed to create socket");
return -1;
}
int broadcast_yes = 1, reuse_yes = 1;
if (setsockopt(socket_fd, SOL_SOCKET, SO_BROADCAST, (void*) &broadcast_yes, sizeof(broadcast_yes)) < 0) {
perror("failed to set broadcast socket option");
return -2;
}
if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, (void*) &reuse_yes, sizeof(reuse_yes)) < 0) {
perror("failed to set reuse socket option");
return -3;
}
memset(&receiver, 0, sizeof(receiver));
receiver.sin_family = AF_INET;
receiver.sin_port = htons(PORT);
receiver.sin_addr.s_addr = INADDR_ANY;
if (bind(socket_fd, (struct sockaddr*) &receiver, sizeof(receiver)) < 0) {
perror("failed to bind");
return -4;
}
printf("Listening...\n");
memset(receive_buff, 0, sizeof(receive_buff));
sender_size = sizeof(sender);
if (recvfrom(socket_fd, (void*)receive_buff, sizeof(receive_buff), 0, (struct sockaddr*) &sender, &sender_size) < 0) {
perror("failed to receive broadcast message");
return -5;
}
printf("%s\n", receive_buff);
strcpy(send_buff, "got your message");
if (sendto(socket_fd, (void*)send_buff, sizeof(send_buff), 0, (struct sockaddr*) &sender, sizeof(sender)) < 0) {
perror("failed to send confirmation message");
return -6;
}
close(socket_fd);
return 0;
}
Code for sender.c (I put this code on my virtual machine):
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 4242
int main() {
int socket_fd;
struct sockaddr_in receiver;
char send_buff[256], receive_buff[256];
socklen_t receiver_size;
socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (socket_fd < 0) {
perror("failed to create socket");
return -1;
}
int broadcast_yes = 1;
if (setsockopt(socket_fd, SOL_SOCKET, SO_BROADCAST, (void*) &broadcast_yes, sizeof(broadcast_yes)) < 0) {
perror("failed to set broadcast socket option");
return -2;
}
memset(&receiver, 0, sizeof(receiver));
receiver.sin_family = AF_INET;
receiver.sin_port = htons(PORT);
receiver.sin_addr.s_addr = inet_addr("192.168.1.255");
strcpy(send_buff, "i'm sending a broadcast message");
if (sendto(socket_fd, (void*)send_buff, strlen(send_buff) + 1, 0, (struct sockaddr*) &receiver, sizeof(receiver)) < 0) {
perror("failed to send broadcast message");
return -3;
}
memset(receive_buff, 0, sizeof(receive_buff));
receiver_size = sizeof(receiver);
if (recvfrom(socket_fd, (void*)receive_buff, sizeof(receive_buff), 0, (struct sockaddr*) &receiver, &receiver_size) < 0) {
perror("failed to receive confirmation message");
return -4;
}
printf("%s\n", receive_buff);
close(socket_fd);
return 0;
}
As you can see, there is nothing fancy. The sender sends the message i'm sending a broadcast message as a broadcast message (since I put 255 at the end of the IPv4 address and I also set the SO_BROADCAST option in the socket). In turn, the receiver waits and receives this message. It also has that SO_BROADCAST option enabled in the socket. What happens afterwards is what is confusing to me. As you can see above after the receiver receives the message, it sends a confirmation message got your message back to the sender.
But what if a sender sends the message to all receivers (listeners) in the LAN and there are MULTIPLE receivers in the LAN, how would this work? Wouldn't EACH of the multiple receivers send that got your message confirmation message to the sender? So it would be like multiple machines have that code in receiver.c and each of these machine would get the sender's address information in the variable struct sockaddr_in sender when the code calls the function recvfrom(). Then, ALL of these machines will send that message got your message to the sender. But the sender has only one recvfrom() function call so it will receive only the first message which arrives to it. The confirmation messages of the other receivers will be lost. Or at least that's what I think is going to happen. How can I solve this and get all the confirmation messages? Again, this question only applies if my understanding of what happens that I stated above is true, which I don't know if it is so I would also ask you if I am correct in thinking that the sender will only receive one confirmation message.
Your understanding is correct.
If you broadcast a message and multiple instances of the receiver get it, each of the will send a response back to the sender.
This means that the sender needs to call recvfrom in a loop to receive multiple messages. But at the same time you don't want the sender to wait forever since you don't know how many responses you'll get.
The simplest way to handle this is to use the select function to check if there's data to read. You can give this function a timeout so you can control how long it waits. If it returns a positive value, there's data to read and you can call recvfrom to read a response, then call select again to wait for more. If it returns 0, then it timed out waiting for a response.
I am writing a server that should wait for client to connect. After accessing the main loop server should "bounce" so long accept() does return a different value then -1. The problem is that the accept() method is blocking the execution instead of returning any value. What could be a reason for this if there is no invalid argument flag raised?
Bellow is a minimum reproducible example of my code:
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/unistd.h> // unlink
#define MAX_LISTCLI 5
int main(void) {
uint server_id, len;
struct sockaddr_un server;
if ((server_id = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("Socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, "free_socket");
if (unlink(server.sun_path) != -1)
fprintf(stderr, "Server was NOT aboard correctly?\n");
len = (strlen(server.sun_path) + sizeof(server.sun_family));
if (bind(server_id, (struct sockaddr *)&server, len) == -1) {
perror("Bind");
exit(1);
}
if (listen(server_id, MAX_LISTCLI) == -1) {
perror("Listen");
exit(1);
}
_Bool done = 0;
while (!done) {
uint remote_id;
struct sockaddr_un remote;
len = sizeof(remote);
// Bounce if connection was not obtained and wait for the client to connect
printf("Connecting..\n");
if ((remote_id =
accept(server_id,
(struct sockaddr *)&remote ,&len)) == -1) {
fprintf(stderr, "Bounce..\n");
continue;
}
fprintf(stderr, "Connected.\n");
// Replay to the user..
done = 1;
}
close(remote_id);
close(server_id);
unlink(server.sun_path);
return 0;
}
The problem here is with the socket being server_id being blocking (refer here).
If no pending connections are present on the queue, and the
socket is not marked as nonblocking, accept() blocks the caller
until a connection is present. If the socket is marked
nonblocking and no pending connections are present on the queue,
accept() fails with the error EAGAIN or EWOULDBLOCK.
If you want the accept call to return immediately you would have to make the socket non blocking.
EDIT: I wouldn't recommend making it a non-blocking call as that would simply waste CPU cycles due to repeated execution of the while loop. The ideal way of dealing with this would block on the accept call and then use fork system call to spawn a new process.
As mentioned in other post, you need to make your server socket nonblocking. You can do that by using fcntl.
fcntl(server_id, F_SETFL, O_NONBLOCK);
Then all of the calls that would normally block your socket will return a flag.
I have developed a tcp server in my one embedded device using lwip+freeRTOS.
Now this is the flow how I communicate with other device ( Other device has Linux system and let's name it LinuxDevice) using my device ( let's name it lwipDevice)
Send UDP packet from lwipDevice to LinuxDevice to initiate that I am ready to share my information.
Now LinuxDevice recognises this message successfully and sends one TCP packet (which contain command) to lwipDevice for telling to send its information.
But at lwipDevice side this message is not received. So it will not send any response to LinuxDevice. And steps 1-3 repeat again and again.
Now this is code of lwipDevice for TCP server:
long server_sock=-1;
#define FAIL 1
#define PASS 0
int CreateTcpServerSocket(long *pSock, int port)
{
struct sockaddr_in sin;
int addrlen = sizeof(sin);
int e;
struct linger linger;
linger.l_linger=0;
int i = 1;
*pSock = socket(AF_INET, SOCK_STREAM, 0);
if (*pSock == -1)
{
printf("*** createTcpSercerSocket:open sock error,port %d\n",port);
return FAIL;
}
memset((char *)&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(sin);
sin.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard IP address */
sin.sin_port = htons(port);
e = bind(*pSock, (struct sockaddr*)&sin, addrlen);
if (e != 0)
{
printf("error %d binding tcp listen on port\n");
closesocket(*pSock);
*pSock = -1;
return FAIL;
}
lwip_ioctl(*pSock, FIONBIO, &i); //Set Non blocking mode
e = listen(*pSock, 2);
if (e != 0)
{
pprintf("error :listen on TCP server\n");
closesocket(*pSock);
*pSock = -1;
return FAIL;
}
return PASS;
}
void vTCPTask(void *parm)
{
struct sockaddr client; /* for BSDish accept() call */
int clientsize;
long sock;
if(CreateTcpServerSocket(&server_sock, 8000) == FAIL) //Here server created successfully
{
printf("Fail to create server!!!!!\n");
server_sock=-1;
}
while(1)
{
// some code for other stuff
sock= accept(server_sock, &client, &clientsize); //This line always fails and reurn -1
if(sock != -1)
{
printf("accepted socket:\n\n");
//...now receive data from client....
// send some data to client
}
// some code for other stuff
//sleep for 15 seconds
}
}
int main()
{
//...initilization of lwip stack
//....some more code
//...................
xTaskCreate(vTCPTask, (signed char const *) "tcptask",
356, NULL, 3, (xTaskHandle *)&xNotifierServiceTaskHandle);
/* Start the scheduler */
vTaskStartScheduler();
return 1
}
I have checked lwip_accept function and it will return from this condition:
if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0))
{
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
sock_set_errno(sock, EWOULDBLOCK);
return -1;
}
EDIT:
I know that netconn_is_nonblocking(sock->conn) condition will always true because have set socket in non blocking mode. But why sock->rcvevent always zero even LinuxDevice already send packet to it?
EDIT:
For testing purpose have commented all other stuff code in task ( see //some code for other stuff ) then socket is successfully accepted and i try to receive the packet but now problem is it's now stuck in lwip_recvfrom function (Note: LinuxDevice continue send packets). So have further debug more and found that it stuck in function sys_arch_mbox_fetch ( function call flow:: lwip_recvfrom\netconn_recv\netconn_recv_data\sys_arch_mbox_fetch).
Does anyone have an idea what is wrong with it?
You have configured the socket as non-blocking, so the accept() call will never block. If there is no incoming connection pending it will return the EWOULDBLOCK error code, which is what you see.
Finally I figured out what is cause of issue.
In lwipopt.h file there is macro like
/* Non-static memory, used with DMA pool */
#ifdef __CODE_RED
#define MEM_SIZE (6 * 1024)
#else
#define MEM_SIZE (24 * 1024)
#endif
I have defined _CODE_RED. So MEM_SIZE will (6 * 1024). Now when i change that memory size to (16 * 1024) then everything working fine.
Now all the time connection accepted and after that i am able to send/recv tcp packets successfully.
Where do you set rcvevent? Your code doesn't reveal it. I suppose it's the result of recv (or read). Reading from a non-blocking that has no available data (haven't yet received data) returns EAGAIN, which evaluates true in your rcvevent <= 0 condition. You have to manually check these specific error codes.
But why sock->rcvevent always zero even LinuxDevice already send packet to it?
Have you tried sending data with telnet or netcat to be sure the error is in your server and not in your client? Maybe your client is not sending to the correct destination, or something else.
Is it possible that a TCP server program can listen on two different socket interface?
Problem Statement:
I've a problem statement where the TCP server will be having two interfaces:
Interface I: For accepting generic data from TCP client (IP address 192.168.5.10:2000)
Interface II: Management Interface for the server (IP address 192.168.5.11:2000)
Interface I: This interface shall receive data from TCP client, processes them & send it back to client.
Interface II: This interface shall receive commands (meant for Servers management purpose). This commands most probably would be sent through telnet.
Current Status:
I already have a thread based TCP server program where I've "Interface I" up & running(I'm able to receive data from multiple clients, process them & send it back)
Can anyone give me some pointers/prototype example on how to add "Interface II" to my TCP server program?
NOTE: TCP server program is written in C programming language for Linux OS
UPDATE
Below is the code fragment I've written so far for listening on one socket. I tried modifying it for listening over two sockets as you've directed but I'm facing trouble while trying to spawn a different thread for the other socket interface. Will it possible for you to modify this to listen on two sockets? It would be really helpful.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
void *data_processing_thread(void *arg);
int main(int argc, char **argv)
{
int fdmax, listener, newfd, res;
int optval=1;
socklen_t addrlen;
int server_port = 4000;
/* master, temp file descriptor list */
fd_set *master, *read_fds;
/* client, server address */
struct sockaddr_in server_addr, client_addr;
pthread_t thread;
master = malloc(sizeof(fd_set));
read_fds = malloc(sizeof(fd_set));
FD_ZERO(master);
FD_ZERO(read_fds);
/* create endpoint for communication */
if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("failed to create listener\n");
return -1;
}
/* check if address is already in use? */
if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(int)) == -1) {
perror("socket address already in use!\n");
return -1;
}
/* bind */
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(server_port);
memset(&(server_addr.sin_zero), '\0', 8);
if (bind(listener, (struct sockaddr*)&server_addr,
sizeof(server_addr)) == -1) {
perror("failed to do the bind\n");
return -1;
}
/* listen for connect on sockets */
if (listen(listener, 10) == -1) {
perror("failed to listen on socket\n");
return -1;
}
/* add the listener to the master set */
FD_SET(listener, master);
/* keep track of biggest file descriptor */
fdmax = listener;
while (1) {
read_fds = master;
/* wait till socket descriptor is ready for the operation */
if (select(fdmax+1, read_fds, NULL, NULL, NULL) == -1) {
perror("failed to do select() on socket\n");
return -1;
}
/* Run through existing data connections looking for data to be
* read */
int cnt;
int *accept_fd = 0;
for (cnt=0; cnt<=fdmax; cnt++) {
if (cnt == listener) {
if (FD_ISSET(cnt, read_fds)) {
addrlen = sizeof(client_addr);
if ((newfd = accept(listener, (struct sockaddr*)&client_addr, &addrlen)) == -1) {
perror("failed to accept incoming connection\n");
} else {
fprintf(stdout, "Server: Connection from client [%s] on socket [%d]\n",
inet_ntoa(client_addr.sin_addr), newfd);
accept_fd = malloc(sizeof(int));
*accept_fd = newfd;
if ((res = pthread_create(&thread, NULL, data_processing_thread, (void*)accept_fd)) != 0) {
perror("Thread creation failed\n");
free(accept_fd);
}
}
}
continue;
}
}
}
return 1;
}
void *data_processing_thread(void *arg)
{
int nbytes;
int *recv_fd = (int*)arg;
char *buffer = malloc(sizeof(char)*256);
while(1) {
fprintf(stdout, "Server: Waiting for data from socket fd %d\n", *recv_fd);
/* receive incoming data from comm client */
if ((nbytes = recv(*recv_fd, buffer, sizeof(buffer), 0)) <= 0) {
if (nbytes != 0) {
perror("failed to receive\n");
}
break;
} else {
fprintf(stdout, "Data received: %s\n", buffer);
}
}
close(*recv_fd);
free(recv_fd);
pthread_exit(0);
}
Create two listening sockets using socket().
Bind both to respective address/port using bind().
Make both listen using listen().
Add both listening sockets to a properly initialised fd_set typed variable using FD_SET().
Pass the fd_set to a call to select()
Upon select()'s return check the reason and perform the appropriate action, typically
either calling accept() on one of the both listening sockets and add the accepted socket (as returned by accept()) to the fd_set,
or if it's an accepted socket that had triggered select() to return, then call read(), write() or close() on it. If close()ing the socket also remove it from the fd_set using FD_CLR().
Start over with step 5.
Important note: The steps above are a rough scheme, not mentioning all possible all traps, so it is absolutly necessary to also read the related man-pages for each step carefully, to understand what is happening.
you can bind 0.0.0.0 which means binding all interfaces.
you can't bind two interfaces using only one socket.
you should create a new socket, and bind ti to interface II.