“ accept”始终返回1,但没有关闭描述符

时间:2019-05-14 19:51:12

标签: c sockets pthreads

该程序伪装成一个简单的服务器-客户端程序,一个线程扫描传入的连接,每个客户端一个新线程建立一个双向通信套接字。 我不关闭stdin,stdout或stderr描述符,但是accept始终返回1(stdout),因此文件描述符不是套接字,当我使用send o recv函数时会触发错误,并且当我使用read或recv时会发生不正确的行为写。 感谢您的阅读。

#include <errno.h>
#include "../../lib/GC.h"
#include <pthread.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>

#include <netdb.h>
#include <netinet/in.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>

#include <string.h>
#include <arpa/inet.h>

typedef struct{
 int socket,stop_service,pos;
 pthread_t tid;
 void *server;
 long client_chunk_max_len;
}tConnectedClient;

typedef struct{
 int socket;
 struct sockaddr_in6 addr;
 struct tSocketOptions{
  int domain,type_and_behavior,protocol;
 }startup_option;
 struct tSocketFDoptions{
  int level,optname,flags;
  void *options;
  socklen_t optlen;
 }socket_option;

 pthread_t tid;
 int stop_service;

 int clients,max_clients;
 tConnectedClient *client;
}tService;

#define CL_BUFFER_SZ 16*1024 //16KB
#define SV_BUFFER_SZ 16*1024 //16KB
#define COMMAND_HELLO 0
#define COMMAND_BYE 1
#define COMMAND_STORE_RESOURCE 2
#define COMMAND_DISPOSE_RESOURCE 3
#define COMMAND_SET_SCENERY 4
#define COMMAND_SET_MOVILE 5
#define COMMAND_MOVE_ITEM 6
#define COMMAND_LIMIT_MOVE_3DITEM 7
#define COMMAND_LIMIT_MOVE_3DITEM_OFF 8
#define COMMAND_LIMIT_NO_MOVE_3DITEM_OFF 9

typedef struct{
 int socket;
 struct sockaddr_in6 addr;
 struct tSocketOptions startup_option;
 char *server_ip;
 bool connected;
 long server_chunk_max_len;
 char client_rcv_data[CL_BUFFER_SZ];
}tClient;

const char say_ok[]={1,0,0,0,0,0,0,0,'+'};

void *client_handler(tConnectedClient *c){
 //TODO gestionar peticiones
 struct pollfd socket_poll={
  fd:c->socket,
  events:POLLIN,
  revents:0
 };
 tService *s=(tService*)c->server; 
 char *buffer=(char*)malloc(SV_BUFFER_SZ);
 int bytes_read,c_socket=c->socket,resources_loaded=0;
 void **resource;
 printf("[INFO]Client tid %d ready on socket %d...\n",c->tid,c_socket);
 int err_lvl;
 do{
  if(err_lvl=poll(&socket_poll,1,10000)>0){
   bytes_read=read(c_socket,buffer,SV_BUFFER_SZ);/*DEBUG*/printf("[DEBUG]bytes_read=%d command=%d len=%d\n",bytes_read,buffer[0],((long*)&buffer[1])[0]);//Reads from descriptor 1, not from "socket"
   if(bytes_read<0){
    printf("Error listening client:\n\t");
    switch(errno){
    case EAGAIN: printf("EAGAIN or EWOULDBLOCK\n");break;
    case EBADF: printf("EBADF\n");break;
    case ECONNREFUSED: printf("ECONNREFUSED\n");break;
    case EFAULT: printf("EFAULT\n");break;
    case EINTR: printf("EINTR\n");break;
    case EINVAL: printf("EINVAL\n");break;
    case ENOMEM: printf("ENOMEM\n");break;
    case ENOTCONN: printf("ENOTCONN\n");break;
    case ENOTSOCK: printf("ENOTSOCK\n");break;
    }
   }else
   switch(buffer[0]){
   case COMMAND_HELLO:{c->client_chunk_max_len=((long*)&buffer[1])[0]; long server_chunk_size=SV_BUFFER_SZ; write(c_socket,&server_chunk_size,sizeof(long));/*DEBUG*/printf("[DEBUG]client_chunk_max_len=%dbytes\n",c->client_chunk_max_len);}break;
   case COMMAND_BYE: c->stop_service=-1; write(c_socket,say_ok,9); break;
   case COMMAND_STORE_RESOURCE:

   break;
   default: printf("Unknow command “%d” from client side\n",buffer[0]);
   }
  }
 }while(!c->stop_service);
 int c_pos;
 s->client[c_pos=c->pos]=s->client[--s->clients];
 s->client[s->clients].pos=c_pos;
 free(buffer);
 printf("[INFO]Client tid %d shutdown\n",c->tid);
 pthread_exit(NULL);
}

void *server_listener(tService *s){//Here is where error happens...
 struct pollfd socket_poll={
  fd:s->socket,
  events:POLLIN,
  revents:0
 };

 /*setsockopt(s->socket=socket(s->startup_option.domain,s->startup_option.type_and_behavior,s->startup_option.protocol),
            s->socket_option.level,s->socket_option.optname,s->socket_option.options,s->socket_option.optlen);
 bind(s->socket,(struct sockaddr*)&s->addr,sizeof(struct sockaddr_in6));
 listen(s->socket,s->max_clients);*///Move init inside does not work...

 int err_lvl;
 do{
  if(err_lvl=poll(&socket_poll,1,10000)>0){
   if(s->clients<s->max_clients){
    int cln=s->clients;
    if(s->client[cln].socket=accept(s->socket,NULL,NULL)>=0){printf("[DEBUG]client socket is %d\n",s->client[cln].socket);//This "accept" always returns 1, but no descriptor has been closed.
     s->client[cln].stop_service=0;
     s->client[cln].pos=cln;
     s->clients++;
     pthread_create(&s->client[cln].tid,NULL,(void*(*)(void*))client_handler,&s->client[cln]);
     printf("[INFO]New incoming client, current load: %d/%d\n",s->clients,s->max_clients);
    }else printf("[WARNING]Error accepting client, no data available? (0x%X)\n",errno);
   }else printf("[INFO]Too many clients, only up to %d allowed, current is %d rejecting...\n",s->max_clients,s->clients);
  }else{
    if(err_lvl==0)printf("[INFO]Server waiting for clients time timeout, retrying...\n");
    else switch(errno){case EFAULT:printf("[WARNING]Server error: EFAULT\n");break;
                       case EINTR:printf("[WARNING]Server error: EINTR\n");break;
                       case EINVAL:printf("[WARNING]Server error: EINVAL\n");break;
                       case ENOMEM:printf("[WARNING]Server error: ENOMEM\n");break;
                      }
   }
 }while(!s->stop_service);
 printf("[INFO]Server thread quits, good bye!!\n");
 for(err_lvl=0;err_lvl<s->clients;err_lvl++){
  atomic_store(&s->client[err_lvl].stop_service,-1);
  pthread_join(s->client[err_lvl].tid,NULL);
 }
 pthread_exit(NULL);
}

tService *setup_service(const char *opt){//TODO config string
 tService *service=(tService*)malloc(sizeof(tService));
 memset(service,0,sizeof(tService));
 service->startup_option.domain=AF_INET6;
 service->startup_option.type_and_behavior=SOCK_STREAM|SOCK_NONBLOCK;
 service->startup_option.protocol=0;

 service->addr.sin6_family=AF_INET6;
 service->addr.sin6_port=htons(5000);
 service->addr.sin6_addr=in6addr_any;

 service->socket_option.options=malloc(service->socket_option.optlen=sizeof(int));
 ((int*)service->socket_option.options)[0]=1;
 service->socket_option.level=SOL_SOCKET;
 service->socket_option.optname=SO_REUSEADDR;

 service->max_clients=2;
 memsetb(service->client=(tConnectedClient*)malloc(sizeof(tConnectedClient)*service->max_clients),0,sizeof(tConnectedClient)*service->max_clients);
 int c=0;for(;c<service->max_clients;c++)service->client[c].server=service;
 return service;
}

void launch_server(tService *service){
 setsockopt(service->socket=socket(service->startup_option.domain,service->startup_option.type_and_behavior,service->startup_option.protocol),
            service->socket_option.level,service->socket_option.optname,service->socket_option.options,service->socket_option.optlen);
 bind(service->socket,(struct sockaddr*)&service->addr,sizeof(struct sockaddr_in6));
 listen(service->socket,service->max_clients);
 pthread_create(&service->tid,NULL,(void*(*)(void*))server_listener,service);
}

int main(int argc,char **argv){
 tService *service=setup_service(NULL);
 launch_server(service);
 printf("[INFO]Server launched...\n");
 getchar();
 atomic_store(&service->stop_service,-1);
 pthread_join(service->tid,NULL);
 printf("[INFO]Server shutdown\n");
 close(service->socket);
 return 0;
}

1 个答案:

答案 0 :(得分:4)

请注意

a = b >= 0;

a设置为b >= 0的布尔结果,而不是b的值。不管b是变量还是函数调用的结果,无论赋值是表达式语句还是if语句中的条件,都是如此。

因此,如果b实际上是通常返回正值的函数,则a通常将以值1结尾。

您的意思可能是if ((a = b) >= 0)…,但总的来说,您最好不要感到困惑:

s->client[cln].socket = accept(s->socket,NULL,NULL);
if ( s->client[cln].socket >= 0 ) …