Сервер и несколько клиентов, использующих pthreads и select()
Рассмотрим следующий кусок кода -
int get_ready_connection(int s) {
/* socket of connection */
int caller;
if ((caller = accept(s,NULL,NULL)) < SUCCESS)
{
server_log->write_to_log(sys_call_error(SERVER, "accept"));
return FAILURE;
}
return caller;
}
int establish_connection(sockaddr_in& connection_info)
{
// Create socket
if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) < SUCCESS)
{
server_log->write_to_log(sys_call_error(SERVER, "socket"));
return FAILURE;
}
// Bind `sock` with given addresses
if (bind(server_sock, (struct sockaddr *) &connection_info, \
sizeof(struct sockaddr_in)) < SUCCESS)
{
close(server_sock);
server_log->write_to_log(sys_call_error(SERVER, "bind"));
return FAILURE;
}
// Max # of queued connects
if (listen(server_sock, MAX_PENDING_CONNECTIONS) < SUCCESS)
{
server_log->write_to_log(sys_call_error(SERVER, "listen"));
return FAILURE;
}
// Create a set of file descriptors and empty it.
fd_set set;
bool is_inside;
int ret_val;
while(true)
{
FD_ZERO(&set);
FD_SET(STDIN_FILENO, &set);
FD_SET(server_sock, &set);
struct timeval tv = {2, 0};
ret_val = select(server_sock + 1, &set, NULL, NULL, &tv); // TODO ret_val
is_inside = FD_ISSET(STDIN_FILENO, &set);
if(is_inside)
{
// get user input
string user_input;
getline(cin, user_input);
if ((strcasecmp(user_input.c_str(), EXIT_TEXT) == 0))
{
return SUCCESS;
}
}
is_inside = FD_ISSET(server_sock, &set);
if(is_inside)
{
// get the first connection request
int current_connection = get_ready_connection(server_sock);
if (current_connection == FAILURE) {
free_allocated_memory();
exit_write_close(server_log, sys_call_error(SERVER, "accept"),
ERROR);
}
// if exit was not typed by the server's stdin, process the request
pthread_t thread;
// create thread
if (pthread_create(&thread, NULL, command_thread_func, ¤t_connection) != 0)
{
free_allocated_memory();
exit_write_close(server_log, sys_call_error(SERVER, "pthread_create"), ERROR);
}
}
}
}
Все, что я пытаюсь сделать, это "прослушать" STDIN, чтобы пользователь набрал "EXIT" в оболочке сервера, и дождаться, пока клиенты передадут команды из своих оболочек (каждый раз, когда сервер получает команду от пользователя, сервер анализирует его, а сервер создает поток, который обрабатывает выполнение команды.) Для одновременного выполнения этой задачи я использовал select().
Когда я работаю с одной нитью, все идеально. Но проблема в том, что когда я подключаю другого клиента, я получаю ошибку сегмента. Я подозреваю, что проблема здесь. какие-либо предложения?
1 ответ
Трудно понять, если это именно ваша проблема, но это определенно проблема:
Ты не можешь позвонить pthread_create
и предоставить указатель на переменную стека (¤t_connection
) в качестве аргумента вашей функции потока. С одной стороны, он подлежит немедленному уничтожению, как только родитель выходит из этой области.
Во-вторых, он будет перезаписан при следующем вызове get_ready_connection
,