When you create a socket, it just have a type and a protocol family. The ideal is to bind() it to a local address/port too.
The error normally happens when the last connection to the same host/port didn't have a graceful shutdown (FIN/ACK FIN/ACK). In these cases, the socket stays in TIME_WAIT state for a certain period of time (OS dependent, but adjustable, at least on *nix).
What happens then is when you try to connect() to the same host and same port, it uses the default socket name/address/port/etc, but this combination is already in use by your zoombie socket. However, you can change the local address/port used to establish the connection. Just call bind() after the socket creation, and provide the sockaddr struct filled with your local address and a random port.
int main() {
int ret, fd;
struct sockaddr_in sa_dst;
struct sockaddr_in sa_loc;
char buffer[1024] = "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
fd = socket(AF_INET, SOCK_STREAM, 0);
// Local
memset(&sa_loc, 0, sizeof(struct sockaddr_in));
sa_loc.sin_family = AF_INET;
sa_loc.sin_port = htons(LOCAL_RANDOM_PORT);
sa_loc.sin_addr.s_addr = inet_addr(LOCAL_IP_ADDRESS);
ret = bind(fd, (struct sockaddr *)&sa_loc, sizeof(struct sockaddr));
assert(ret != -1);
// Remote
memset(&sa_dst, 0, sizeof(struct sockaddr_in));
sa_dst.sin_family = AF_INET;
sa_dst.sin_port = htons(80);
sa_dst.sin_addr.s_addr = inet_addr("64.233.163.104"); // google :)
ret = connect(fd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr));
assert(ret != -1);
send(fd, buffer, strlen(buffer), 0);
recv(fd, buffer, sizeof(buffer), 0);
printf("%s\r\n", buffer);
}
Update: As using a specific local port is a requirement, consider setting SO_LINGER with l_onoff=1 and l_linger=0, then your socket won't block upon close/closesocket
, it will just ignore queued data, and (hopefully) close the fd. Or ultimately, adjusting the TIME_WAIT delay changing the value of this registry key:
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay