Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C-如何循环一个套接字_C_Sockets_Printf_Cycle_Select Function - Fatal编程技术网

C-如何循环一个套接字

C-如何循环一个套接字,c,sockets,printf,cycle,select-function,C,Sockets,Printf,Cycle,Select Function,我有一个程序,可以打印我发送的文件的内容: struct addrinfo hints; struct addrinfo *serverInfo; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; getaddrinfo(NULL, PUERTO, &hints, &serverInfo); //socket para escu

我有一个程序,可以打印我发送的文件的内容:

struct addrinfo hints;
struct addrinfo *serverInfo;

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;

getaddrinfo(NULL, PUERTO, &hints, &serverInfo);
//socket para escuchar
int listenningSocket;
listenningSocket = socket(serverInfo->ai_family, serverInfo->ai_socktype, serverInfo->ai_protocol);
bind(listenningSocket,serverInfo->ai_addr, serverInfo->ai_addrlen);
freeaddrinfo(serverInfo);

listen(listenningSocket, BACKLOG);
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
int socketCliente = accept(listenningSocket, (struct sockaddr *) &addr, &addrlen);
char package[PACKAGESIZE];
int status = 1;

printf("\nCliente conectado. Esperando mensajes:\n");
printf("\nEl contenido del script es: \n");

while (status != 0) {
    status = recv(socketCliente, (void*) package, PACKAGESIZE, 0);
    if (status != 0) printf("%s", package);
}
close(socketCliente);
close(listenningSocket);

但我想让这个程序听其他我想打印的东西。所以我需要循环套接字,监听套接字。我知道我需要
select()
函数,但我不知道如何在代码中使用它。

您需要在循环中调用
select()
(或者更好的是,
epoll()
),在这里,您传递其
readfds
参数一个
fd\u集
,其中包含侦听套接字描述符和所有连接的客户端套接字描述符。当退出
select()
时,它将告诉您哪些套接字上有挂起的可读数据

如果侦听套接字有挂起的数据要读取,请对其调用
accept()
,如果成功,则将返回的套接字描述符添加到某个跟踪列表中,以便您可以将其包含在对
select()
的后续调用中

如果任何其他套接字都有待读取的数据,请对其调用
recv()
,并根据需要对其数据执行操作。如果
recv()
在任何给定套接字上返回-1或0,则
关闭该套接字描述符并将其从跟踪列表中删除,以便在后续调用
select()
时忽略它

也就是说,所有套接字调用都缺少足够的错误处理。它们中的任何一个都可能失败,您不知道这对
recv()
特别重要,因此您可以正确地检测和清理任何断开/丢失的客户端连接

另外,您假设
recv()
总是返回以null结尾的字符串,但事实并非如此。客户端可以发送以null结尾的字符串,但不能保证在一次读取中读取整个以null结尾的字符串。您必须在循环中调用
recv()
,缓冲其间接收到的任何数据,直到实际接收到空终止符,然后继续处理完成的字符串

尝试类似的方法(伪代码,用于根据需要填写客户机跟踪列表的实现细节):

struct addrinfo提示;
结构addrinfo*serverInfo;
memset(&hints,0,sizeof(hints));
hits.ai_family=AF_INET;
hits.ai_socktype=SOCK_流;
if(getaddrinfo(NULL、PUERTO、提示和服务器信息)<0){
//TODO:错误处理。。。
返回-1;
}
//牙套
int listenningSocket=socket(serverInfo->ai_系列,serverInfo->ai_socktype,serverInfo->ai_协议);
如果(ListeningSocket<0){
//TODO:错误处理。。。
freeaddrinfo(serverInfo);
返回-1;
}
if(绑定(listenningSocket,serverInfo->ai_addr,serverInfo->ai_addrlen)<0){
//TODO:错误处理。。。
freeaddrinfo(serverInfo);
关闭(监听插座);
返回-1;
}
freeaddrinfo(serverInfo);
if(侦听(listenningSocket,BACKLOG)<0){
//TODO:错误处理。。。
关闭(监听插座);
返回-1;
}
地址中的结构sockaddr\u;
索克伦·阿德伦;
int socketCliente,maxfd,status;
字符包[PACKAGESIZE];
char*str;
结构timeval超时;
someList客户端;//TODO:由您决定实施。。。
而(!someStopCondition){//TODO:由您决定实现。。。
fd_集rfd;
FD_零(&rfd);
FD_集(listenningSocket和rfd);
maxfd=listenningSocket;
对于(客户端中的每个fd){//TODO:由您决定。。。
FD_集(FD和rfd);
如果(fd>maxfd){
maxfd=fd;
}
}
//TODO:由你决定。。。
timeout.tv_sec=。。。;
timeout.tv_usec=。。。;
状态=选择(maxfd+1,&rds,NULL,NULL,&timeout);
如果(状态<0){
//TODO:错误处理。。。
打破
}
如果(状态==0){
//TODO:根据需要做其他事情。。。
持续
}
if(FD_ISSET(侦听套接字和rds)){
addrlen=sizeof(addr);
socketCliente=accept(listenningSocket,(struct sockaddr*)&addr,&addrlen);
如果(socketCliente<0){
//TODO:错误处理。。。
}
否则如果(!addToList(&clients,socketCliente)){//TODO:由您决定实现。。。
//TODO:错误处理。。。
关闭(socketCliente);
}否则{
printf(“\nCliente conconnectado.Esperando mensajes:\n”);
}
}
对于(客户端中的每个fd){//TODO:由您决定。。。
如果(FD_ISSET(FD和rfd)){
状态=recv(fd,package,PACKAGESIZE,0);

if(需要调用
accept()的状态)
在循环中。每次连接进入时,它都会返回一个新的描述符。当
recv
返回一个错误时,值将
-1
,并且不会填充
。另外,想想当接收到的数据不是像字符串那样以零结尾时会发生什么。还有,你怎么会认为t“package”缓冲区将始终包含一个很好的以null结尾的字符串吗?“package”缓冲区将始终包含一个很好的以null结尾的字符串,因为我发送的所有脚本都是这样终止的。在这里,我只需要使用select循环Listening和acept,但我不知道如何使用它。您不是在发送脚本,而是在发送一个byte流和您的“状态”(如果>0)告诉您recv()调用已接收到这些字节中的多少个。这可能介于1和PACKAGESIZE之间,通常不会以null结尾。