Kea*_*her 2 c sockets client tcp
我用 C 语言编写了一个简单的服务器。它应答端口 8888 上的连接。它工作得很好......直到我尝试将它作为后台进程运行。
当我像这样运行时
$ ./server
Run Code Online (Sandbox Code Playgroud)
然后尝试与客户端连接,它工作正常。当我尝试像这样运行它时:
$ ./server &
Run Code Online (Sandbox Code Playgroud)
或者如果我像这样运行它
$ ./server
Run Code Online (Sandbox Code Playgroud)
然后使用 CTRL+z 将其分离并尝试与我得到的客户端连接
Connection Refused
Run Code Online (Sandbox Code Playgroud)
以前有人遇到过这个问题吗?我将非常感谢一个解决方案。
accept( )以下是根据要求调用的代码:
char remoteIP[ INET6_ADDRSTRLEN ];
int yes=1; /* for setsockopt() SO_REUSEADDR, below */
int i, rv;
struct addrinfo hints, *ai, *p;
FD_ZERO( &master ); /* clear the master and temp sets */
FD_ZERO( &read_fds );
/* get us a socket and bind it */
memset( &hints, 0, sizeof hints );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ( ( rv = getaddrinfo( NULL, URL_PORT, &hints, &ai ) ) != 0 )
{
/* fprintf( stderr, "selectserver: %s\n", gai_strerror( rv ) ); */
exit( 1 );
}
/* printf( "Listening on port %s for URLs...\n", URL_PORT ); */
for( p = ai; p != NULL; p = p->ai_next )
{
listener = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
if ( listener < 0 )
{
continue;
}
/* lose the pesky "address already in use" error message */
setsockopt( listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof( int ) );
if ( bind( listener, p->ai_addr, p->ai_addrlen) < 0 )
{
close( listener );
continue;
}
break;
}
/* if we got here, it means we didn't get bound */
if ( p == NULL )
{
/* fprintf( stderr, "selectserver: failed to bind\n" ); */
exit( 2 );
}
freeaddrinfo( ai ); /* all done with this */
/* listen */
if ( listen( listener, 10 ) == -1 )
{
perror( "listen" );
exit( 3 );
}
/* add the listener to the master set */
FD_SET( listener, &master );
/* keep track of the biggest file descriptor */
fdmax = listener; /* so far, it's this one */
/* main loop */
for( ; ; ) {
for( i = 0; i <= fdmax; i++ )
{
if ( SOCKETS[ i ].in_progress )
{
if ( pthread_join( SOCKETS[ i ].thread, NULL ) != 0 )
{
/* fprintf( stderr, "Error terminating thread %i\n", i ); */
}
else
{
SOCKETS[ i ].in_progress = FALSE;
}
}
}
read_fds = master; /* copy it */
if ( select( fdmax + 1, &read_fds, NULL, NULL, NULL ) == -1 )
{
perror( "select" );
exit(4);
}
/* run through the existing connections looking for data to read */
for( i = 0; i <= fdmax; i++ ) {
if ( FD_ISSET( i, &read_fds ) && SOCKETS[ i ].in_progress == FALSE )
{
/* we got one!! */
if ( i == listener )
{
/* handle new connections */
addrlen = sizeof remoteaddr;
newfd = accept( listener, ( struct sockaddr * ) &remoteaddr, &addrlen );
if ( newfd == -1 )
{
perror( "accept" );
}
else
{
FD_SET( newfd, &master ); /* add to master set */
if ( newfd > fdmax )
{ /* keep track of the max */
fdmax = newfd;
}
/*
printf(
"selectserver: new connection from %s on socket %d\n",
inet_ntop( remoteaddr.ss_family, get_in_addr( ( struct sockaddr* ) &remoteaddr ), remoteIP, INET6_ADDRSTRLEN ), newfd );
*/
}
}
Run Code Online (Sandbox Code Playgroud)
您的进程从其控制终端读取或写入,因此当您在后台运行它时,它会被 SIGTTIN 或 SIGTTOU 停止&。
bash 手册页的相关摘录:
仅允许前台进程读取或写入终端。尝试从终端读取(写入)的后台进程会由终端驱动程序发送 SIGTTIN (SIGTTOU) 信号,除非被捕获,否则该进程将挂起。
SIGTTOU 的发送由默认情况下关闭的标志控制,因此您的问题可能是由从控制终端读取引起的。如果要阻止后台进程写入终端(即重新启用向尝试后台写入的进程发送 SIGTTOU),请使用以下命令:
stty tostop
Run Code Online (Sandbox Code Playgroud)
您可以使用以下命令恢复默认行为:
stty -tostop
Run Code Online (Sandbox Code Playgroud)
当您按 Ctrl+Z 时,您会导致 SIGTSTP 被发送到进程。该信号的默认处理也是停止进程。如果您希望进程继续在后台运行,请使用以下命令:
bg %1
Run Code Online (Sandbox Code Playgroud)
请注意,您的职位编号可能会有所不同。使用命令检查job。
请注意,与 SIGSTOP 不同,如果您不喜欢这种行为,您的进程可以处理或忽略这三个信号。然后读/写系统调用将返回 EINTR 而不是阻塞。