Here's the code:
if (!isconnected){ printf("Connecting to %s\n",inet_ntoa(outlink_addr.sin_addr)); if (connect(outsock, (struct sockaddr *)&outlink_addr,sizeof(struct sockaddr)) == -1) { perror("connect"); //close(outsock); //exit(1); }else{ printf("Connected to %s (%d)\n",inet_ntoa(outlink_addr.sin_addr),outsock); FD_SET(outsock, &master); // add to master set if (outsock > fdmax) { // keep track of the maximum outsock = newfd; } isconnected = 1; } }
And the output:
Unreal2Hybrid: new connection from 192.168.0.2 on socket 4
Connecting to 63.110.124.45
connect: Transport endpoint is already connected
I can't figure out why it can't reconnect (it connects once, and only once, do I need to reset the struct or something?).
And yes, this is using select, a modified select thingy from Beej. If you want I can post the entire code...
Theres a nice option called something like: SO_REUSEADDR.
Most probably the problem is in the bind, not the connect.
It is an operative system issue. If you don't close the socket correctly (in example, press CTRL-C to end the program), the port is never freed. In Linux there used to be a delay of around 30 seconds-1 minute until the OS freed the socket and you were able to bind it again.
Heres a little function I found and modified:
1 | int make_socket (unsigned short port) |
2 | { |
3 | int sock, yes = 1; |
4 | struct sockaddr_in name; |
5 | |
6 | /* Create the socket. */ |
7 | sock = socket (PF_INET, SOCK_STREAM, 0); |
8 | if (sock < 0) { |
9 | /*char *buf = calloc(1, 256); |
10 | if(!buf) |
11 | exit (EXIT_FAILURE); |
12 | */ |
13 | log_printf(global_log, LOG_LEVEL_FATAL, "socket: failed..."/*, strerror_r(errno, buf, 256)*/); |
14 | //free(buf); |
15 | exit (EXIT_FAILURE); |
16 | } |
17 | if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(const char *)&yes,sizeof(int)) == -1) { |
18 | /*char *buf = calloc(1, 256); |
19 | if(!buf) |
20 | exit (EXIT_FAILURE); |
21 | */ |
22 | log_printf(global_log, LOG_LEVEL_FATAL, "setsockopt: failed..."/*, strerror_r(errno, buf, 256)*/); |
23 | //free(buf); |
24 | exit (EXIT_FAILURE); |
25 | } |
26 | |
27 | /* Give the socket a name. */ |
28 | name.sin_family = AF_INET; |
29 | name.sin_port = htons (port); |
30 | name.sin_addr.s_addr = htonl (INADDR_ANY); |
31 | if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) { |
32 | char *buf = calloc(1, 256); |
33 | if(!buf) |
34 | exit (EXIT_FAILURE); |
35 | |
36 | log_printf(global_log, LOG_LEVEL_FATAL, "bind: failed..."/*, strerror_r(errno, buf, 256)*/); |
37 | //free(buf); |
38 | exit (EXIT_FAILURE); |
39 | } |
40 | |
41 | log_printf(global_log, LOG_LEVEL_NOTE, "Succsessfully bound to port: %i", port); |
42 | |
43 | return sock; |
44 | } |
The log_* functions are mine, not libc or anything... Oh, and note, this is for a server style port IIRC.
How is the server code? It is listening for more connections?
The server listens for connections, and if it find that when a client connects that it's not connected to another server, then it connects to it...
I want it to reconnect to that socket if the connection is lost.
EDIT: Why do you have to bind when connecting to something else?
The code is old, you don't want to open a new port everytime you connect to something
You should show the server code, though. The client should not have problem no matter how many they are.
I edited it so that it recalled the socket thingy...
1 | if (!isconnected){ |
2 | printf("Connecting to %s (cached)\n",inet_ntoa(outlink_addr.sin_addr)); |
3 | if (connect(outsock, (struct sockaddr *)&outlink_addr,sizeof(struct sockaddr)) == -1) { |
4 | perror("connect"); |
5 | if ((outlink=gethostbyname("palace.morphforest.com")) == NULL){ |
6 | perror("gethostbyname"); |
7 | exit(1); |
8 | } |
9 | if ((outsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { |
10 | perror("socket"); |
11 | exit(1); |
12 | } |
13 | outlink_addr.sin_family = AF_INET; // host byte order |
14 | outlink_addr.sin_port = htons(7029); // short, network byte order |
15 | outlink_addr.sin_addr = *((struct in_addr *)outlink->h_addr); |
16 | memset(&(outlink_addr.sin_zero), '\0', 8); // zero the rest of the |
17 | |
18 | // lose the pesky "address already in use" error message |
19 | if (setsockopt(outsock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { |
20 | perror("setsockopt"); |
21 | exit(1); |
22 | } |
23 | printf("Connecting to %s (last attempt)\n",inet_ntoa(outlink_addr.sin_addr)); |
24 | if (connect(outsock, (struct sockaddr *)&outlink_addr,sizeof(struct sockaddr)) == -1) { |
25 | perror("connect"); |
26 | exit(1); |
27 | }else{ |
28 | printf("Connected to %s (%d)\n",inet_ntoa(outlink_addr.sin_addr),outsock); |
29 | FD_SET(outsock, &master); // add to master set |
30 | if (outsock > fdmax) { // keep track of the maximum |
31 | outsock = newfd; |
32 | } |
33 | isconnected = 1; |
34 | } |
35 | //close(outsock); |
36 | //exit(1); |
37 | }else{ |
38 | printf("Connected to %s (%d)\n",inet_ntoa(outlink_addr.sin_addr),outsock); |
39 | FD_SET(outsock, &master); // add to master set |
40 | if (outsock > fdmax) { // keep track of the maximum |
41 | outsock = newfd; |
42 | } |
43 | isconnected = 1; |
44 | } |
45 | } |
Hmm... close the old socket before creating a new one. And you meant reusing a socket to connect? Ah... I misunderstood, sorry.
The old one is automatically closed on error or disconnect.
This seems to work though.
Hmm... really? It frees the descriptor? Geez... it must have changed since the last time I did some real network programming then...
Yeah, it reuses file descriptors, the lowest one free (hense if you close stout and open a new file, all stout will go to the file...
That's the logic between piping stout, you close it then you ddup it or whatever...