linux socket编程问题,下面是我做的一个简单的模拟银行排队叫号系统。
程序运行:开启多个终端,一个服务器,其余的是客户端(包括一个取号机和多个柜台叫号机)
问题:我把服务器和多个客户端程序可以正常运行,但当我按 ctr+c 键杀掉一个客户端后,服务器端的程序也会死掉,
请问怎样才能使 杀死客户端程序 而不使服务器端程序死掉? 要怎样修改程序,请高手指教。
下面是我的源程序:
服务器 server.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <netdb.h>
#include <pthread.h>
/* 定义端口号,须大于1024 */
#define PORT 8888
//#define BUF_SIZE 1024
/* 信息宏 */
#define GEN_GOTAL 1 /* 普通业务总人数 */
#define GEN_CUR 2 /* 普通业务当前服务的号码 */
#define VIP_TOTAL 3 /* vip业务总人数 */
#define VIP_CUR 4 /* vip业务当前服务的号码 */
#define FROM_GET_NUM 5 /* 为取号机创建线程 */
#define FROM_CALL_NUM 6 /* 为叫号机创建线程 */
/* 存储服务人数信息结构定义 */
typedef struct
{
int gen_total_num; /* 普通业务总人数 */
int gen_cur_num; /* 普通业务当前服务的号码 */
int vip_total_num; /* vip业务总人数 */
int vip_cur_num; /* vip业务当前服务的号码 */
}info_bank;
info_bank info_people;
/* 线程执行函数负责读写 */
void *server_client( void *arg );
/* 初始化服务信息 */
void init_info(info_bank *info_people);
void save_info_getnum(info_bank *info_people, int operation); /*保存取号机发来的信息*/
void save_info_call(info_bank *info_people, int operation); /*保存叫号机发来的信息*/
int main(int argc, char *argv[])
{
socklen_t clt_addr_len;
int listen_fd;
int com_fd;
int ret;
int i;
static char recv_buf;
int len;
pthread_t tid;
struct sockaddr_in clt_addr;
struct sockaddr_in srv_addr;
init_info(&info_people);
/* 创建套接字用于服务器的监听 */
listen_fd = socket(PF_INET, SOCK_STREAM, 0);
if (listen_fd < 0)
{
perror("cannot create listening socket");
return 1;
}
/* 填充关于服务器的套节字信息 */
memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sin_family=AF_INET;
srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
srv_addr.sin_port=htons(PORT);
/* 将服务器和套节字绑定 */
ret = bind(listen_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
if (ret == -1)
{
perror("cannot bind server socket");
close(listen_fd);
return 1;
}
/* 监听指定端口,连接5个客户端 */
ret = listen(listen_fd,5);
if (ret == -1)
{
perror("cannot listen the client connect request");
close(listen_fd);
return 1;
}
while(1)
{
len = sizeof(clt_addr);
com_fd = accept(listen_fd, (struct sockaddr *)&clt_addr, &len);
if (com_fd<0)
{
if (errno == EINTR)
{
continue;
}
else
{
perror("cannot accept client connect request");
close(listen_fd);
return 1;
}
}
/* 打印建立连接的客户端产生的套节字 */
printf("com_fd=%d\n", com_fd);
if ((pthread_create(&tid,NULL,server_client,&com_fd))==-1)
{
perror("pthread_create error");
close(listen_fd);
close(com_fd);
return 1;
}
}
return 0;
}
//线程执行函数负责读写
void *server_client(void *arg)
{
int size,j;
int operation;
int server_type,recv_buf,call_buf;
int *parg = (int *)arg;
int new_fd = *parg;
printf("new_fd=%d\n",new_fd);
/* 每创建一个线程时:读取一个数字,确认为哪个客户端服务 */
read(new_fd,&server_type,sizeof(server_type));
if (server_type == FROM_GET_NUM)
{
while(1)
{
printf("operation machine that get number \n");
read(new_fd,&recv_buf,sizeof(recv_buf));
operation = recv_buf;
printf("operation = %d\n", operation);
printf("Message from client recv_buf = %d\n",recv_buf);
save_info_getnum(&info_people, operation);
/* 把保存人数信息的结构体发送跟取号端 */
write(new_fd, &info_people, sizeof(info_people));
sleep(2);
}
}
/* 处理叫号机 */
if (server_type == FROM_CALL_NUM)
{
while(1)
{
printf("AAAAA\n");
read(new_fd,&call_buf,sizeof(call_buf));
operation = call_buf;
printf("operation = %d\n", operation);
printf("Message from client call_buf: %d\n",call_buf);
save_info_call(&info_people, operation);
write(new_fd, &info_people, sizeof(info_people));
sleep(2);
}
}
close(new_fd); // 杀掉一个进程后就全部死掉的原因在这吗????????。
return 0;
}
void init_info(info_bank *info_people)
{
(*info_people).gen_total_num = 5;
(*info_people).gen_cur_num = 1;
(*info_people).vip_total_num = 10;
(*info_people).vip_cur_num = 0;
printf("gen_total_num = %d \n", (*info_people).gen_total_num);
printf("gen_cur_num = %d \n", (*info_people).gen_cur_num);
printf("vip_total_num = %d \n", (*info_people).vip_total_num);
printf("vip_cur_num = %d \n", (*info_people).vip_cur_num);
}
/*保存取号机发来的信息*/
void save_info_getnum(info_bank *info_people, int operation)
{
switch (operation)
{
case GEN_GOTAL:
(*info_people).gen_total_num++;
break;
case VIP_TOTAL:
(*info_people).vip_total_num++;
break;
default:
printf("not this operation \n");
}
printf("gen_total_num = %d \n", (*info_people).gen_total_num);
printf("gen_cur_num = %d \n", (*info_people).gen_cur_num);
printf("vip_total_num = %d \n", (*info_people).vip_total_num);
printf("vip_cur_num = %d \n", (*info_people).vip_cur_num);
}
/*保存叫号机发来的信息*/
void save_info_call(info_bank *info_people, int operation)
{
switch (operation)
{
case GEN_CUR:
(*info_people).gen_cur_num++;
break;
case VIP_CUR:
(*info_people).vip_cur_num++;
break;
default:
printf("not this operation \n");
}
printf("gen_total_num = %d \n", (*info_people).gen_total_num);
printf("gen_cur_num = %d \n", (*info_people).gen_cur_num);
printf("vip_total_num = %d \n", (*info_people).vip_total_num);
printf("vip_cur_num = %d \n", (*info_people).vip_cur_num);
}
客户端:取号机client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#include <unistd.h>
#define PORT 8888
#define SERVER_IP "192.168.1.119"
/* 信息宏 */
#define GEN_GOTAL 1 /* 普通业务总人数 */
#define GEN_CUR 2 /* 普通业务当前服务的号码 */
#define VIP_TOTAL 3 /* vip业务总人数 */
#define VIP_CUR 4 /* vip业务当前服务的号码 */
#define FROM_GET_NUM 5 /* 为取号机创建线程 */
#define FROM_CALL_NUM 6 /* 为叫号机创建线程 */
/* 存储服务人数信息结构定义 */
typedef struct
{
int gen_total_num; /* 普通业务总人数 */
int gen_cur_num; /* 普通业务当前服务的号码 */
int vip_total_num; /* vip业务总人数 */
int vip_cur_num; /* vip业务当前服务的号码 */
}info_bank;
info_bank info_people;
int main(int argc,char *argv[])
{
int connect_fd;
int ret;
int snd_buf;
int i;
//int port;
int len;
static struct sockaddr_in srv_addr;
/*创建套节字用于客户端的连接 */
connect_fd=socket(PF_INET, SOCK_STREAM, 0);
if (connect_fd < 0)
{
perror("cannot create communication socket");
return 1;
}
/* 填充关于服务器的套节字信息 */
memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sin_family=AF_INET;
srv_addr.sin_addr.s_addr=inet_addr(SERVER_IP);
srv_addr.sin_port=htons(PORT);
/*连接指定的服务器 */
ret=connect(connect_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
if(ret==-1)
{
perror("cannot connect to the server");
close(connect_fd);
return 1;
}
//memset(snd_buf, 0, BUF_SIZE);
/* 发送一个字符A个服务器,服务器收到字符A后就知道是取号机发来的 */
//strcpy(snd_buf,"A");
snd_buf = FROM_GET_NUM;
write(connect_fd,&snd_buf,sizeof(snd_buf));
//memset(snd_buf, 0, BUF_SIZE);
while(1)
{
printf("AAAAA\n");
snd_buf = VIP_TOTAL;
write(connect_fd, &snd_buf, sizeof(snd_buf));
printf("BBBBB\n");
//memset(snd_buf, 0, BUF_SIZE);
//read(connect_fd,&snd_buf,sizeof(snd_buf));
printf("CCCCC\n");
/* 接收服务器发来的保存人数的结构体 */
read(connect_fd,&info_people,sizeof(info_people));
printf("gen_total_num = %d \n", info_people.gen_total_num);
printf("gen_cur_num = %d \n", info_people.gen_cur_num);
printf("vip_total_num = %d \n", info_people.vip_total_num);
printf("vip_cur_num = %d \n", info_people.vip_cur_num);
sleep(2);
//close(connect_fd);
}
close(connect_fd);
return 0;
}
叫号机跟取号机时差不多的。
[解决办法]
服务端的socket设置非阻塞模式
[解决办法]
设个 信号处理,signal(SIGTERM, 重启);
其实可以用子进程处理,随你kill