Two clients getting the same file descriptor for TCP connection to a server

Hello Everybody!

I am picking up network programming and I am following Beej's Guide to Network Programming. Its been great so far, but now I came to a problem where I am stuck. I would appreciate a lot if you could point me in a right direction.

So what I have is a TCP server and 3 clients all launched in separate threads, at a same time (example below).
Sever is using Select to detect new connections and saves them in a list, while clients doing a simple connect as per Beej's tutorial. All clients connecting to the same port number on server.

Problem is that some times clients indicate that they all got connected, while server indicates that it accepted only 1 or 2 connections. Also socket file descriptors of some clients have identical values.

Could you please advice what could be the problem here? I can post the rest of the code if needed.

Thanks a lot!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

int main() {
	srand (time(NULL));
	port = rand()%4000 + 1000;


	sprintf(buffer,"%d",port);

	pthread_t t_ServerCom, t_ClientCom1, t_ClientCom2, t_ClientCom3 ;

	pthread_create( &t_ServerCom, NULL, &run_t_ServerCom_3, (void*)NULL);


	int n1 = 1;
	int n2 = 2;
	int n3 = 3;
	pthread_create( &t_ClientCom1, NULL, &run_t_ClientCom_3, (void*)&n1);
	pthread_create( &t_ClientCom2, NULL, &run_t_ClientCom_3, (void*)&n2);
	pthread_create( &t_ClientCom3, NULL, &run_t_ClientCom_3, (void*)&n3);

	pthread_join( t_ServerCom, NULL);
	pthread_join( t_ClientCom1, NULL);
	pthread_join( t_ClientCom2, NULL);
	pthread_join( t_ClientCom3, NULL);

	cout<<"Main Exit\n";

	return 0;

}


What's in run_t_ClientCom_3 ?
This is the rest:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
using namespace std;
int port = 0;
char buffer[20];
inline void *get_in_addr(struct sockaddr *sa)
{
	if (sa->sa_family == AF_INET) {
		return &(((struct sockaddr_in*)sa)->sin_addr);
	}
	return &(((struct sockaddr_in6*)sa)->sin6_addr);
}


vector<int> waitForClientConnections(const char* addr, const char* port, int nClients, int timeOut = 0){
	cout<<"Waiting for connection"<<endl;
	struct addrinfo   addrHint;
	struct addrinfo*  addrList;
	struct addrinfo*  addrIter;

	int fd_inConSocket;
	int fd_retConSocket;

	vector<int> vfd_clients;

	fd_set read_fdsSet;


	struct sockaddr_storage remoteaddr; // client address


	memset(&addrHint, 0, sizeof addrHint);
	addrHint.ai_family = AF_UNSPEC;
	addrHint.ai_socktype = SOCK_STREAM;
	addrHint.ai_flags = AI_PASSIVE;

	int err;
	if ((err = getaddrinfo(addr, port, &addrHint, &addrList)) != 0) {
		fprintf(stderr, "selectserver: %s\n", gai_strerror(err));
		exit(1);
	}


	for(addrIter = addrList; addrIter != NULL; addrIter = addrIter->ai_next) {
		fd_inConSocket = socket(addrIter->ai_family, addrIter->ai_socktype, addrIter->ai_protocol);
		if (fd_inConSocket < 0) {
			continue;
		}
		int yes=1;
		// lose the pesky "address already in use" error message
		setsockopt(fd_inConSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
		if (bind(fd_inConSocket, addrIter->ai_addr, addrIter->ai_addrlen) < 0) {
			close(fd_inConSocket);
			continue;
		}
		break;
	}

	if (addrIter== NULL) {
		// if we got here, it means we didn't get bound
		fprintf(stderr, "selectserver: failed to bind\n");
		exit(2);
	}

	freeaddrinfo(addrList); // all done with this

	if (listen(fd_inConSocket, 10) == -1) {
		perror("listen");
		exit(3);
	}


	FD_ZERO(&read_fdsSet);


	FD_SET(fd_inConSocket, &read_fdsSet);

	int fdmax = fd_inConSocket;
	int ccount = 0;
	while(ccount<nClients) {
		//cout<<"SR_ITER"<<ccount<<endl;
		/**
		 * In this select we are monitoring read_fds list for it to be ready to receive data from them
		 */
		if (select(fdmax+1, &read_fdsSet, NULL, NULL, NULL) == -1) {
			perror("select");
			exit(4);
		}
		/**
		 *  run through the existing connections looking for data to read
		 */
		for(int i = 0; i <= fdmax; i++) {
			if (FD_ISSET(i, &read_fdsSet)) { // we got one!!

				if (i == fd_inConSocket) {
					// handle new connections
					socklen_t addrlen;
					addrlen = sizeof remoteaddr;
					char remoteIP[INET6_ADDRSTRLEN];

					int fd_newInCon = accept(fd_inConSocket,
							(struct sockaddr *)&remoteaddr,
							&addrlen);


					if (fd_newInCon == -1) {
						cout<<"EEEEEEEEEEEEEEEEEEEEE\n";
						perror("accept");

					} else {
						/**
						 *This is very important, we have added new connection file descriptor to our listeners set.
						 */
						FD_SET(fd_newInCon, &read_fdsSet); // add to master set

						if (fd_newInCon > fdmax) {
							// keep track of the max
							fdmax = fd_newInCon;
						}
						vfd_clients.push_back(fd_newInCon);
						ccount++;
						printf("SelectServer: new connection from %s on "
								"socket %d\n",
								inet_ntop(remoteaddr.ss_family,
										get_in_addr((struct sockaddr*)&remoteaddr),
										remoteIP, INET6_ADDRSTRLEN),
										fd_newInCon);
					}
				}
			}
		}

	}

	return vfd_clients;

}


/**
 *
 * @param addr String address of the connection
 * @param port Port to wich we connecting to
 * @param timeOut sec. When we give up on trying to connect to a server
 * @return int connection file descriptor
 *         -1 on Error.
 */
int connectToServer(const char* addr, const char* port, int timeOut = 0){
	cout<<"connectToServer "<<addr<<":"<<port<<endl;
	struct addrinfo trialAddrInfo; // using this to initially get an idea of the address that we trying to connect to.
	struct addrinfo *addrInfoList;
	struct addrinfo* iterInfo = NULL;


	int fd_socket = -1;


	memset(&trialAddrInfo, 0 , sizeof trialAddrInfo);

	trialAddrInfo.ai_family = AF_UNSPEC;
	trialAddrInfo.ai_socktype = SOCK_STREAM;
	trialAddrInfo.ai_flags = AI_PASSIVE; // fill in information for me.


	int getAddrInfoReturnError;
	if ((getAddrInfoReturnError = getaddrinfo("127.0.0.1", port, &trialAddrInfo, &addrInfoList)) != 0) {
		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(getAddrInfoReturnError));
		return -1;
	}


	struct timeval timeStart;
	struct timeval timeCurrent;
	long timeDif = 0;

	gettimeofday( &timeStart, NULL);

	/**
	 * We are trying to reconnect until we succeed.
	 * Or until we time out if timer has been set > 0.
	 * If no timer is set we are looping indefinitely.
	 */
	while ((iterInfo == NULL)  &&
			(( (timeOut > 0) && (timeOut >= timeDif)) || (timeOut == 0))  ){

		for (iterInfo = addrInfoList ; iterInfo != NULL;  iterInfo = iterInfo->ai_next){
			if ((fd_socket = socket(iterInfo->ai_family, iterInfo->ai_socktype, iterInfo->ai_protocol)) == -1){
				perror("ERROR Client socket:");
				continue;
			}

			if (connect(fd_socket, iterInfo->ai_addr, iterInfo->ai_addrlen) == -1){
				close(fd_socket);
				perror("ERROR Connect error");
				continue;
			}

			/**
			 * If we have ended up here everyting is ok! :)
			 */
			break;

		}

		if (iterInfo == NULL){

			gettimeofday( &timeCurrent, NULL);

			timeDif = timeCurrent.tv_sec  - timeStart.tv_sec;

			cout<<"We have not find a socket that we could connect to "<<addr<<":"<<port<<" Time pass:"<<timeDif<<endl;
			sleep(1);

		}
	}
	cout<<"Client ENDing "<<iterInfo<<" "<<fd_socket<<endl;

	if ((iterInfo == NULL) &&
			(timeOut > 0) &&
			(timeOut <= timeDif)){
		cout<<"We have timed out on a connection\n";
		fd_socket = -1;
	}

	freeaddrinfo(addrInfoList);

	return fd_socket;

}


void *run_t_ServerCom_3(void* Q){
	cout<<__FUNCTION__<<endl;


	vector<int> vfd_socketList = waitForClientConnections("127.0.0.1", buffer, 3);
	if (vfd_socketList.size() == 0){
		cout<<"FATAL ERROR We did not established connection with client"<<endl;
		return NULL;
	}
	int a;
	cout<<"SR_Exit"<<endl;

	close(vfd_socketList.at(0));
}

void *run_t_ClientCom_3(void* n){
	cout<<__FUNCTION__<<" "<<*(int*)n<<endl;


	int fd_socket = connectToServer("127.0.0.1", buffer );
	if (fd_socket == -1){
		perror("ERROR FATAL We did not established connection with client");
		return NULL;
	}

	cout<<"CL_Exit"<<*(int*)n<<endl;

	close(fd_socket);
}
Probably your server isn't active while the clients are running.
Maybe you just waited until one of them connected, and when it connected you instantly stopped the server.

When you will keep the server running, this problem will disappear.

I'm really not sure about this tho, your code isn't the cleanest and I'm not used to unix (even if I tried to help).
This is sample output from this program, during the time when its working incorrectly.

run_t_ClientCom_3 1
connectToServer 127.0.0.1:4085
run_t_ServerCom_3
Waiting for connection
ERROR Connect error: Connection refused
We have not find a socket that we could connect to 127.0.0.1:4085 Time pass:0
run_t_ClientCom_3 2
connectToServer 127.0.0.1:4085
SelectServer: new connection from 127.0.0.1 on socket 5
Client ENDing 0x7f46cc0008c0 3
CL_Exit2
run_t_ClientCom_3 3
connectToServer 127.0.0.1:4085
Client ENDing 0x7f46c00008c0 3
CL_Exit3
Client ENDing 0x7f46d00008c0 3
CL_Exit1



From here you can see that 3 clients are exiting connectToServer function and printing
Client ENDing 0x7f46cc0008c0 3
And all of them printing "3" for the value of the file descriptor (I assume this should be different to all of them)
But server acknowledge only single connection by printing "new connection from 127.0.0.1 on socket 5" this means only single accept has been called.
Server never exits while(ccount<nClients) loop, because its waiting for another 2 clients to connect.

There is a possibility that Server initially is not up and we seeing "ERROR Connect error: Connection refused" message, but this is alright, since Clients will try to reconnect.

Thanks for the help! hope this will clarify a bit what I am trying to do here.
Topic archived. No new replies allowed.