gpt4 book ai didi

c - 如何在 C 中的 TCP 服务器已经阻塞时将其从阻塞模式更改为非阻塞模式或者如何正确关闭阻塞的 TCP 服务器?

转载 作者:可可西里 更新时间:2023-11-01 02:49:10 25 4
gpt4 key购买 nike

我对运行 TCP 服务器没有任何问题,我喜欢它处于阻塞状态以避免无用的循环、休眠代码和无用的 cpu 周期这一事实。

问题发生在 Linux 环境下关闭它时,它一直亮着,直到连接的用户发送了一些东西,然后它关闭。

我认为这是因为它在阻塞,即使无休止的 while 循环设置为退出。但是当它阻塞时,将套接字 ID 更改为 NON_BLOCKING 根本没有帮助,很可能必须在阻塞发生之前将其设置为 NON_BLOCKING。

#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h> /* Added for the nonblocking socket */

#define LISTEN_MAX 10 /* Maximum clients that can queue up */
#define LISTEN_PORT 32000
#define MAX_COMMANDS_AT_ONCE 4000
#define NANO_SECOND_MULTIPLIER 1000000 // 1 millisecond = 1,000,000 Nanoseconds

//Global so I can access these where I shut the threads off.
int listenfd, connfd; //sockets that must be set to non-blocking before exiting

int needQuit(pthread_mutex_t *mtx)
{
switch(pthread_mutex_trylock(mtx)) {
case 0: /* if we got the lock, unlock and return 1 (true) */
pthread_mutex_unlock(mtx);
return 1;
case EBUSY: /* return 0 (false) if the mutex was locked */
return 0;
}
return 1;
}

/* this is run on it's own thread */
void *tcplistener(void *arg)
{
pthread_mutex_t *mx = arg;
//keyboard event.

SDLKey key_used;
struct timespec ts;
//int listenfd,connfd,
int n,i, ans;
struct sockaddr_in servaddr,cliaddr;
socklen_t clilen;
pid_t childpid;
char mesg[MAX_COMMANDS_AT_ONCE];

listenfd=socket(AF_INET,SOCK_STREAM,0);

bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(LISTEN_PORT);
int option = 1;
if(setsockopt(listenfd, SOL_SOCKET,SO_REUSEADDR,(char*)&option,sizeof(option)) < 0)
{
printf("setsockopt failed\n");
close(listenfd);
}
bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

listen(listenfd,LISTEN_MAX);

while( !needQuit(mx) )
{
clilen=sizeof(cliaddr);
connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);

while( !needQuit(mx) )
{
n = recv(connfd,mesg,MAX_COMMANDS_AT_ONCE,0);

if(n == 0 || n == -1) break;
//...Do Stuff here with mesg...
}
}
close(connfd);
}

close(connfd);
close(listenfd);
return NULL;
}

int main(int argc, char *argv[])
{
/* this variable is our reference to the thread */
pthread_t tcp_listener_thread;
pthread_mutex_t mxq; /* mutex used as quit flag */

/* init and lock the mutex before creating the thread. As long as the
mutex stays locked, the thread should keep running. A pointer to the
mutex is passed as the argument to the thread function. */
pthread_mutex_init(&mxq,NULL);
pthread_mutex_lock(&mxq);

/* create a hread which executes tcplistener(&x) */
if(pthread_create(&tcp_listener_thread, NULL, tcplistener, &mxq)) {
fprintf(stderr, "Error creating TCP Listener thread\n");
//clear thread for tcp listener on exit.
/* unlock mxq to tell the thread to terminate, then join the thread */
fcntl(listenfd, F_SETFL, O_NONBLOCK); /* Change the socket into non-blocking state */
fcntl(connfd, F_SETFL, O_NONBLOCK); /* Change the socket into non-blocking state */

pthread_mutex_unlock(&mxq);
pthread_join(tcp_listener_thread,NULL);
pthread_cancel(tcp_listener_thread);
pthread_exit(NULL);
return 0;
}

//End of the TCP Listener thread.


// Waits 500 milliseconds before shutting down
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 500 * NANO_SECOND_MULTIPLIER;
nanosleep((&ts, NULL);

//Forces a shutdown of the program and thread.
//clear thread for tcp listener on exit.
/* unlock mxq to tell the thread to terminate, then join the thread */
fcntl(listenfd, F_SETFL, O_NONBLOCK); /* Change the socket into non-blocking state */
fcntl(connfd, F_SETFL, O_NONBLOCK); /* Change the socket into non-blocking state */
pthread_mutex_unlock(&mxq);
pthread_join(tcp_listener_thread,NULL);
pthread_cancel(tcp_listener_thread);
pthread_exit(NULL);
return 0;
}

我尝试了 EJP 建议的修复,但仍然挂起..我已经将 connfdlistenfd 设为全局作用域

pthread_mutex_unlock(&mxq); 
close(connfd); //<- this
close(listenfd); //<-- this
pthread_join(tcp_listener_thread,NULL);
pthread_cancel(tcp_listener_thread);
pthread_exit(NULL);

最佳答案

要取消阻塞 accept(),只需关闭监听套接字即可。确保 accept() 句柄周围的代码是正确的。

要解除对 recv() 的阻塞,请关闭输入的接收套接字。这将导致 recv() 返回零,必须再次正确处理。或者像上面那样关闭套接字,如果您希望接收代码知道您正在关闭应用程序,这可能会更好。

关于c - 如何在 C 中的 TCP 服务器已经阻塞时将其从阻塞模式更改为非阻塞模式或者如何正确关闭阻塞的 TCP 服务器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22262270/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com