C 如何停止侦听并仅从一个用户接收数据,并在他断开连接时重新开始侦听
我正在尝试编写一个服务器客户端程序。这个想法是服务器C 如何停止侦听并仅从一个用户接收数据,并在他断开连接时重新开始侦听,c,sockets,network-programming,network-protocols,C,Sockets,Network Programming,Network Protocols,我正在尝试编写一个服务器客户端程序。这个想法是服务器 在给定端口上侦听() 当用户连接时,它接受()连接并停止侦听 当用户断开连接时,它将返回到侦听状态,并且这种情况将永远持续下去 现在,我已经创建了服务器,通信进展顺利,但是,我不确定当用户连接时如何停止监听,并在断开连接时开始监听。有人能帮我吗 另外,我正在遵循beejs指南 谢谢停止收听的唯一方法是关闭收听插座。这对已接受的连接没有影响,因此它们可以继续使用。要重新开始侦听,您需要打开一个新的侦听套接字并将其绑定。如果要在TCP延迟时间过去
这完全取决于您希望客户端在尝试连接到繁忙的服务器时看到什么。使服务器在接受连接时拒绝客户端连接的唯一方法是关闭(2)用于接受(2)连接的套接字 不可能让内核一次拒绝一个连接上的连接。内核仅在没有套接字侦听的情况下拒绝连接 下面是一个服务器示例,其中接受套接字在连接之间关闭,因此如果启动第二个连接,第二个连接将出现
econnreference
错误
但这有一个竞争条件:如果服务器程序在accept(2)
和close(2)
系统调用之间连接第二个连接,则服务器将打开(和关闭)第二个连接,并且不会出错。如果第二个连接中的客户端尝试读取(2)
,则会收到来自服务器的eof,如果客户端尝试写入(2)
,则会收到错误
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define F(_fmt) __FILE__":%d:%s: "_fmt, __LINE__, __func__
#define ERR(_ex_cod, _fmt, ...) do { \
fprintf(stderr, \
F("ERROR: "_fmt), \
##__VA_ARGS__); \
if (_ex_cod) \
exit(_ex_cod); \
} while (0)
char *
sockaddr2str(
struct sockaddr_in *addr,
char *buf,
size_t bufsz)
{
char *ret_val = buf;
snprintf(buf, bufsz,
"%s:%d",
inet_ntoa(addr->sin_addr),
ntohs(addr->sin_port));
return ret_val;
}
int main()
{
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(12345);
for(;;) {
int acc_sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (acc_sockfd < 0)
ERR(EXIT_FAILURE,
"socket: %s\n", strerror(errno));
/* this is needed in case you need to reopen it in a short time. */
int reuse_addr = 1;
int res = setsockopt(
acc_sockfd,
SOL_SOCKET, SO_REUSEADDR,
&reuse_addr, sizeof reuse_addr);
if (res < 0)
ERR(EXIT_FAILURE,
"setsockopt: %s\n", strerror(errno));
res = bind(
acc_sockfd,
(struct sockaddr *) &server_addr,
sizeof server_addr);
if (res < 0)
ERR(EXIT_FAILURE,
"bind: %s\n", strerror(errno));
/* 0 listen(2) will make the queue size 0, so only
* connections that enter while server is accept()ing
* them will enter */
res = listen(acc_sockfd, -1);
if (res < 0)
ERR(EXIT_FAILURE,
"listen: %s\n", strerror(errno));
struct sockaddr_in client_addr;
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = INADDR_ANY;
client_addr.sin_port = 0;
socklen_t client_addr_sz = sizeof client_addr;
int conn_sockfd = accept(
acc_sockfd,
(struct sockaddr *)&client_addr,
&client_addr_sz);
if (res < 0)
ERR(EXIT_FAILURE,
"accept: %s\n", strerror(errno));
close(acc_sockfd);
char client_name[256];
sockaddr2str(&client_addr,
client_name, sizeof client_name);
char buff[1024];
printf("Connection from %s\n", client_name);
FILE *f = fdopen(conn_sockfd, "r");
if (!f)
ERR(EXIT_FAILURE,
"fdopen: %s\n", strerror(errno));
int c;
while((c = fgetc(f)) != EOF) {
size_t n = snprintf(
buff, sizeof buff,
"[%02x]%s",
c,
c == '\n'
? "\r\n"
: "");
write(conn_sockfd, buff, n);
if (c == '\033') break;
}
printf("Connection from %s ended\n", client_name);
close(conn_sockfd);
fclose(f);
}
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义F(_fmt)uu文件::%d:%s:“_fmt,uu行,u函数”__
#定义错误(_ex_cod,_fmt,…)do{\
fprintf(标准\
F(“错误:”_fmt)\
##__VA_ARGS_uu)\
如果(_ex_cod)\
出口(货到付款)\
}而(0)
煤焦*
sockaddr2str(
*地址中的结构sockaddr_,
char*buf,
尺寸(bufsz)
{
char*ret_val=buf;
snprintf(buf,bufsz,
“%s:%d”,
inet\u ntoa(地址->sin\u地址),
ntohs(地址->sin_港);
返回返回值;
}
int main()
{
服务器地址中的结构sockaddr\u;
服务器地址sin家庭=AF网络;
server\u addr.sin\u addr.s\u addr=INADDR\u ANY;
服务器地址sin端口=htons(12345);
对于(;;){
int acc_sockfd=套接字(PF_INET,SOCK_STREAM,0);
如果(acc_sockfd<0)
ERR(退出故障),
“套接字:%s\n”,strerror(errno));
/*这是必要的,以防你需要重新打开它在短时间内*/
int reuse_addr=1;
int res=setsockopt(
acc_sockfd,
SOL_插座,所以,
&重复使用地址、重复使用地址的大小);
如果(res<0)
ERR(退出故障),
“设置锁选项:%s\n”,strerror(errno));
res=绑定(
acc_sockfd,
(结构sockaddr*)和服务器地址,
服务器的大小(地址);
如果(res<0)
ERR(退出故障),
“绑定:%s\n”,strerror(errno));
/*0侦听(2)将使队列大小为0,因此仅
*在服务器接受()时输入的连接
*他们会进来的*/
res=监听(acc_sockfd,-1);
如果(res<0)
ERR(退出故障),
“侦听:%s\n”,strerror(errno));
客户端地址中的结构sockaddr\u;
氯