EOF doesn't flag to POLLIN?

I'm thinking cause POLLIN only watches for bytes incoming. And I can't do this...

1
2
3
4
int poll_activity = 0;
while(poll_activity==0){
poll_activity = (poll_sockets_ptr, poll_sockets.size(), 0);
}


It will still block because poll doesn't read anything on POLLIN about getting flagged for EOF

What other events should I add to the client sockets? POLLRDHUP?

I would very much love to keep the block and don't want to go back to constantly checking through all these sockets for EOF. It spikes my CPU up 20% and with blocking it gets down to only 1-3% usage!
Last edited on
Define "EOF". What is it exactly that you're "constantly checking"? poll() reports connection termination without any extra work.
EOF as in zero bytes read(), which ultimately means connection is closed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Pollfd init
//Add master_socket 
pollfd *poll_sockets_ptr;
int poll_activity = 0;
while(server_online){
while(poll_activity==0){
poll_sockets_ptr = &poll_sockets[0]
poll_activity = poll(poll_sockets_ptr, poll_sockets.size(), 0);
}
for(int i=0; i< poll_sockets.size(); i++){
if(poll_sockets[i].revents & POLLIN){
   //if i == 0, then it is master server, accept inc. connection
   //if i>0
   //if read == 0 then disconnected else received a message
}
}
}


It'll unblock when the master socket receives connections or the clients send anything to the server but when the client disconnects. poll_activity stays at a 0 thus keeps blocking
Last edited on
You are not even calling poll.
when the client disconnects. poll_activity stays at a 0 thus keeps blocking

That can't be true, every other network application in the world would stop working. If you have a compilable testcase, it could be possible to help in debugging it.

Here's a brief (although it's never brief with sockets API) demo

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int ac, char* av[])
{
    if(ac != 2 || atoi(av[1]) <= 0) {
        printf("Usage: %s <port_to_listen>\n", av[0]);
        return 1;
    }

    int s = socket(AF_INET, SOCK_STREAM, 0); // error checking skipped

    struct sockaddr_in a;
    memset(&a, 0, sizeof a);
    int port = atoi(av[1]);
    a.sin_port = htons(port);
    a.sin_family = AF_INET;
    bind(s, (struct sockaddr*)&a, sizeof a); // error checking skipped

    printf("Waiting for a connection on port %d\n", port);
    listen(s, 0); // error checking skipped

    struct sockaddr_in client_addr;
    socklen_t l = sizeof client_addr;
    int r = accept(s, (struct sockaddr*)&client_addr, &l); // error checking skipped
    fcntl(r, F_SETFD, O_NONBLOCK);

    // will error check poll() since this is what it's about
    while(1)
    {
        struct pollfd pfd = {r, POLLIN, 0};
        if(poll(&pfd, 1, 0) < 0) {
            perror("poll");
            close(s);
            return 1;
        }
        if(   pfd.revents & POLLNVAL
           || pfd.revents & POLLERR
           || pfd.revents & POLLHUP )
        {
            printf("poll() detected an error or a hangup\n");
            return 1;
        }
        if(pfd.revents & POLLPRI) {
            char byte;
            recv(r, &byte, 1, MSG_OOB);
            printf("poll() indicates OOB data: %d\n", (int)byte);
        }
        if(pfd.revents & POLLIN) {
            char byte;
            int readrc = read(r, &byte, 1);
            if(readrc == 0) {
                printf("poll() indicates POLLIN, read returns 0: orderly shutdown\n");
                break;
            }
            printf("poll() indicates data to read: 0x%x", (int)byte);
            if(isprint(byte))
                printf(" (%c)", byte);
            printf("\n");
        }
    }
}


tested on linux, aix, and solaris by running echo "test" | nc localhost 12346 in one terminal and this program in another:

 ./test 12346
Waiting for a connection on port 12346
poll() indicates data to read: 0x74 (t)
poll() indicates data to read: 0x65 (e)
poll() indicates data to read: 0x73 (s)
poll() indicates data to read: 0x74 (t)
poll() indicates data to read: 0xa
poll() indicates POLLIN, read returns 0: orderly shutdown


PS: If you're using C++, use boost.asio, it's a lot simpler, safer, and more efficient too.
Last edited on
Whoops didn't type poll sorry retyped the whole program on a mobile device. The real program has poll in it


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
//============================================================================
// Name        : drawdown_server.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#define _GNU_SOURCE
#include <stdio.h>
#include <iostream>
#include <pthread.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include <unistd.h>
#include <vector>

#include <poll.h>
#include "server_socket.h"


#define PORT 6666
#define BUFFSIZE 255
using namespace std;

struct sockaddr_in address;
int master_socket;
bool server_online;
int test_user_count = 1;
struct player {
	int socket;
	int database_id;
	int online; // 0 OFFLINE (SAVE), 1 ONLINE, 2 SAVED
	bool available; // 1 AVAILABLE,  0 NOT AVAILABLE
	string first_name;
	string profile_picture;
	int points;
	int wins;
	int diamonds;
	int sos;
};
struct request {
	int socket;
	player* player_info;
	string action;
	vector<string> token;
	vector<int> token_int;
};
pthread_mutex_t players_lock;
vector<request> database_requests;
vector<request> game_requests;
vector<player> players;
vector<vector<player*> > main_queue;

void* connectionThread(void*) {
	vector<pollfd> poll_sockets;
	pollfd* poll_sockets_ptr;
	pollfd main_socket;
	main_socket.fd = master_socket;
	main_socket.events = POLLIN;
	poll_sockets.push_back(main_socket);
	int addrlen = sizeof(address);
    int poll_activity = 0;
	while (server_online) {
		
        while(poll_activity == 0){
            poll_sockets_ptr = &poll_sockets[0];
		poll_activity = poll(poll_sockets_ptr, poll_sockets.size(), 0);
        }
		if (poll_activity < 0) {
			perror("poll");
		}
		if (poll_sockets[0].revents & POLLIN) {
			int new_socket;
			if ((new_socket = accept(master_socket, (struct sockaddr*) &address,
                                     (socklen_t*) &addrlen)) < 0) {
				perror("accept");
			}
			cout << "Client " << new_socket << " ("
            << inet_ntoa(address.sin_addr) << ":"
            << ntohs(address.sin_port) << ") has connected!" << endl;
			pollfd add_socket;
			add_socket.fd = new_socket;
			add_socket.events = POLLIN;
			poll_sockets.push_back(add_socket);
			char *success_msg = "SUCCESSFUL_CONNECTION;\0";
			int success_msg_len = sizeof(success_msg);
			if( send(new_socket, success_msg, strlen(success_msg), 0) != strlen(success_msg) )
            {
                perror("send");
            }
            
		}
		for (int i = 0; i < poll_sockets.size(); i++) {
			int s = poll_sockets[i].fd;
			if (i != 0) {
				if (poll_sockets[i].revents & POLLIN) {
					char buffer[BUFFSIZE];
					if ((read(s, buffer, BUFFSIZE)) == 0) {
						cout << "Client " << s << " has disconnected!" << endl;
                        close(poll_sockets[i].fd);
						poll_sockets.erase(poll_sockets.begin() + i);
						pthread_mutex_lock(&players_lock);
						for (int b = 0; b < players.size(); b++) {
							if (players[b].socket == s) {
								players[b].online = 0;
							}
						}
						pthread_mutex_unlock(&players_lock);
					} else {
                        cout << buffer  << endl;
						vector<string> client_messages;
						char *msg_tok;
						msg_tok = strtok(buffer, ";");
						while (msg_tok != NULL) {
							client_messages.push_back(msg_tok);
							msg_tok = strtok(NULL, ";");
						}
						bool is_player_logged_in = false;
						player *player_pointer;
						pthread_mutex_lock(&players_lock);
						for (int a = 0; a < players.size(); a++) {
							if (s == players[a].socket) {
								is_player_logged_in = true;
								player_pointer = &players[a];
							}
                            
						}
						pthread_mutex_unlock(&players_lock);
						if (client_messages.size() == 3) {
							if (client_messages[0] == "LOGIN"
                                && !is_player_logged_in) {
                                cout << "received login " << endl;
								request add_request;
								add_request.socket = s;
								add_request.action = client_messages[0];
								add_request.token.push_back(client_messages[1]);
								add_request.token.push_back(client_messages[2]);
								database_requests.push_back(add_request);
							}
						}
						if (client_messages.size() == 2) {
							if (client_messages[0] == "JOIN_QUEUE"
                                && is_player_logged_in) {
								request add_request;
								add_request.socket = s;
								add_request.action = client_messages[0];
								add_request.token_int.push_back(
                                                                atoi(client_messages[1].c_str()));
								add_request.player_info = player_pointer;
								game_requests.push_back(add_request);
							}
						}
					}
				}
			}
		}
        
	}
	return 0;
}
void initServer() {
    master_socket = socket(AF_INET,SOCK_STREAM,0);
    address.sin_port = htons(6666);
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    if((bind(master_socket, (struct sockaddr*) &address, sizeof(address)))<0){
        perror("bind");
    }
    if((listen(master_socket, 20))<0){
        perror("listen");
    }
    server_online = true;
    }
bool close_server() {
	close(master_socket);
}
int main(int argc, char* argv[]) {
	initServer();
	pthread_t t1;
	if (pthread_mutex_init(&players_lock, NULL) != 0) {
		perror("mutexlock");
		exit(EXIT_FAILURE);
	}
	pthread_create(&t1, NULL, connectionThread, NULL);
//	pthread_create(&t2, NULL, gameRequestThread, NULL);
//	pthread_create(&t3, NULL, databaseRequestThread, NULL);
//	pthread_create(&t4, NULL, saveSweepThread, NULL);
	pthread_join(t1, NULL);
//	pthread_join(t2, NULL);
//	pthread_join(t3, NULL);
//	pthread_join(t4, NULL);
	pthread_mutex_destroy(&players_lock);
	if (close_server()) {
		return 0;
	}
    
}


I will look into boost.asio though!
Last edited on
Found it, rather than put 0 as a timeout, I should put -1 for blocking.
Topic archived. No new replies allowed.