该程序伪装成一个简单的服务器-客户端程序,一个线程扫描传入的连接,每个客户端一个新线程建立一个双向通信套接字。 我不关闭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;
}
答案 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 ) …