Мой вопрос точно такой же, как в заголовке.
Это традиционная серверная программа, где в основном потоке я создаю, связываю и слушаю сокет.После создания сокета я жду вызова select, чтобы определить любой запрос клиентского соединения.При получении нового соединения вызов select сбрасывается, я принимаю соединение с помощью функции accept и передаю fd , возвращенную им, клиентскому потоку, где он ожидает выберите вызовите снова для доступности данных.
while(1)
{
select() call waiting on fd
recv() on select release
}
Как и ожидалось, вызов select немедленно освобождается, и я могу получить данные, используя recv функция.
За этим следует интересная часть.После извлечения данных с использованием recv они снова и переходят к функции select , как указано в приведенном выше коде sudo.Здесь я ожидаю, что функция select должна дождаться получения новых данных в сокете fd.Но, к моему удивлению, он немедленно освобождается и переходит к функции recv . (Которая возвращает ошибку EINVAL)
Мой вопрос: почему функция select освобождается?сразу во второй раз.Я немного знаком с сокетами, поэтому любая помощь приветствуется.
Редактировать: проблема, о которой я упоминал выше, заключается в том, что я сталкиваюсь с одним из проектов, над которым я работаю, чтобы изолировать, отладить и понять проблему.Лучше я создал образец приложения, которое имитирует исходную проблему.Таким образом, добавление примера приложения здесь.
#include "stdio.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
/* waits on select call for getting connection request */
int waitForData(int sock_fd)
{
int result = 0;
fd_set rfds;
struct timeval tv;
FD_ZERO ( &rfds );
FD_SET ( sock_fd, &rfds );
tv.tv_sec = 10;
tv.tv_usec = 0;
while(1)
{
result = select ( sock_fd+1, &rfds, NULL, NULL, &tv);
if ( -1 == result )
{
if ( errno == EINTR )
{
/*
** Select interrupted by a signal.
** tv is updated for time remaining, restart select()
*/
continue;
}
printf("select fails\n");
return -1;
}
else if ( 0 == result )
{
printf("select timeouts\n");
return -2;
}
else
{
if(FD_ISSET(sock_fd, &rfds))
{
printf("COM_Select - Fd is set\n");
return 0;
}
else
{
printf("COM_Select - Fd is NOT set\n");
return -1;
}
}
}//while
}//End of waitForData
void* client_thread(void* ptr_argument)
{
if(ptr_argument == 0)
{
printf("Invalid client_sockfd passed to client thread\n");
return 0;
}
int client_sockfd = *((int*)ptr_argument);
printf("Client: client_sockfd: %d\n", client_sockfd);
char data[501];
printf("Client is launched\n");
while(1)
{
printf("Waiting for incoming data...\n");
int waitResult = waitForData(client_sockfd);
if(waitResult == 0)
{
int data_len = 0;
(void)memset(data, 0, sizeof(data));
data_len = recv(client_sockfd, data, 500, 0);
if (data_len == -1)
{
if ( (errno == EWOULDBLOCK) || (errno == EAGAIN) )
printf("Data is being blocked, should try again..\n");
printf("\r\nrecv Error (client_sockfd %d, Error %d)", client_sockfd, errno);
// break;
}
else if(data_len == 0)
{
// Disconnect received
printf("\r\nrecv Disconnect (client_sockfd %d)", client_sockfd);
// break;
}
else
{
printf("Data received successfully\n");
}
printf("data: %s\n", data);
}
else if(waitResult != -2)
{
printf("Error in client wait: %d\n", waitResult);
}
char ch;
scanf("%c", &ch);
}
}
class Server
{
public:
/* Constructor */
Server()
{
mListenFd = 0;
}
/* Destructor */
~Server()
{}
/* Creates and initializes socket */
bool createSocket()
{
mListenFd = socket(AF_INET, SOCK_STREAM, 0);
if (mListenFd == -1)
{
printf("\r\nsocket Error (Error %d)", errno);
return false;
}
int optval = 1;
socklen_t optlen = sizeof(optval);
setsockopt(mListenFd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);
int fcntl_flags = 0;
// Switch the server socket to non-blocking mode
fcntl_flags = fcntl(mListenFd, F_GETFL, 0);
fcntl(mListenFd, F_SETFL, fcntl_flags | O_NONBLOCK);
memset(&mSockAddr, 0, sizeof(struct sockaddr_in));
mSockAddr.sin_family = AF_INET;
mSockAddr.sin_port = htons(502);
mSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(mListenFd, (struct sockaddr *)(&mSockAddr), sizeof(struct sockaddr_in) ) == -1)
{
printf("\r\nbind Error (iFd %d, Error %s)", mListenFd, strerror(errno));
close(mListenFd);
return false;
}
if(listen(mListenFd, 5) == -1)
{
printf("\r\nlisten Error (mListenFd %d, Error %d)", mListenFd, errno);
close(mListenFd);
return false;
}
return true;
}// createSocket
/* waits on select call for getting connection request */
int waitForConnRequest()
{
int result = 0;
fd_set rfds;
// struct timeval tv;
FD_ZERO ( &rfds );
FD_SET ( mListenFd, &rfds );
// tv.tv_sec = 1;
// tv.tv_usec = 0;
printf("Waiting for incoming connections...\n");
while(1)
{
result = select ( mListenFd+1, &rfds, NULL, NULL, 0);
if ( -1 == result )
{
if ( errno == EINTR )
{
/*
** Select interrupted by a signal.
** tv is updated for time remaining, restart select()
*/
continue;
}
return -1;
}
else if ( 0 == result )
{
return -1;
}
else
{
if(FD_ISSET(mListenFd, &rfds))
{
printf("COM_Select - Fd is set\n");
return 0;
}
else
{
printf("COM_Select - Fd is NOT set\n");
return -1;
}
}
}//while
}//End of waitForConnRequest
/* accepts the incoming connection request and creates a client thread */
int acceptConnection()
{
int accept_fd = -1;
struct linger server_linger ={0};
int fcntl_flags = 0;
socklen_t addr_len = sizeof(struct sockaddr_in);
if (mListenFd <= 0)
{
printf("\r\nAccept on INVALID_SOCKET\n");
return -1;
}
accept_fd = accept(mListenFd, (struct sockaddr *)(&mSockAddr), &addr_len);
if (accept_fd == -1)
{
if ((errno == EWOULDBLOCK)||(errno == EAGAIN)||(errno == ECONNABORTED))
return -1;
else
{
printf("\r\nconnect Error (accept_fd %d, Error %d)", accept_fd, errno);
return -1;
}
}
// Set linger timeout to 0, so connections do not remain in TIME_WAIT
server_linger.l_onoff = 1;
server_linger.l_linger = 0;
setsockopt(accept_fd, SOL_SOCKET, SO_LINGER, (char*)&server_linger, sizeof(server_linger));
// Set to non-blocking
fcntl_flags = fcntl(accept_fd, F_GETFL, 0);
fcntl(accept_fd, F_SETFL, fcntl_flags | O_NONBLOCK);
return accept_fd;
}
int createClient(int client_sockfd)
{
int result = 0;
pthread_t thread_id;
pthread_attr_t attr;
int rc;
rc = pthread_attr_init(&attr);
if (rc == -1)
{
printf("error in pthread_attr_init");
close(client_sockfd);
exit(1);
}
rc = pthread_attr_setstacksize(&attr, 4*1024*1024);
if (rc == -1)
{
close(client_sockfd);
printf("error in pthread_attr_setstacksize");
exit(2);
}
/**
* Start thread
*/
int* p_fd = new int;
*p_fd = client_sockfd;
printf("createClient: client_sockfd: %d\n", client_sockfd);
result = pthread_create(&thread_id, &attr, client_thread, p_fd);
if(0 != result)
{
//printf("main: ERROR: pthread_create for %d thread failed with error = %d\n", thread, result);
printf("thread creation failed\n");
return -1;
}
return 0;
}
void startServer()
{
if(createSocket())
{
while(1)
{
if(waitForConnRequest() == 0)
{
int client_sockfd = acceptConnection();
if(client_sockfd != -1 && client_sockfd != 0)
{
printf("Server: creating client: client_sockfd: %d\n", client_sockfd);
if(-1 == createClient(client_sockfd))
{
close(client_sockfd);
printf("Error creating client thread.\nQuitting..\n");
break;
}
}
}
}// while(1)
}//createSocket
printf("\n\nUn expected error in the startServer method\n");
}
private:
int mListenFd;
struct sockaddr_in mSockAddr;
};
int main()
{
Server inst_srvr;
inst_srvr.startServer();
printf("Bye!!\n");
}
Пожалуйста, игнорируйте отладочные сообщения, комментарии, любые утечки памяти или ошибки.
Таким образом, в основном клиентский поток после запуска сервером ожидаетданные в client_sockfd , а затем извлекают данные с помощью функции recv .Затем немедленно переходит к функции select , здесь, так как я получил данные в предыдущем вызове функции recv , я ожидаю, что функция select будет ждать, покавремя ожидания (в этом случае будет возвращено -2).Но функция select всегда выполняется успешно и возвращает 0. Итак, для повторения вопроса, почему select всегда выполняется успешно.
Пожалуйста, предоставьте некоторые предложения.