📄 tcpserver12.c
字号:
//-----------------------排队机服务器端------------------
// 文 件 名:tcpserver11.c
//
// 摘 要:程序启动后首先开一个线程检测键盘。如果键盘输入"exit" 退出
//
// 然后循环等待客户端连接.每有一个新连接就开新线程作相应请求处理.
// 根据收到的客户端信息 “A” (人民币) 或者 “B” (外币)
// 进行入队操作。是回车则进行出对操作。"Q" 则关闭与此客户的连接
// 关闭相应的线程.
//
// 作 者:钟树青
//
// 完成日期:2007-11-21
//
// 更改时间: 2007-11-22
// 更改内容: 解决了服务器卡死状态。
//
// 更改时间: 2007-11-23
// 更改内容: 增加了服务器管理功能.
//
// 备 注:服务器管理不完善.
//
//-----------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <pthread.h>
#include <unistd.h>
#include <malloc.h>
#define MAXDATASIZE 100 /*每次最大数据传输量 */
//**********************************对列结构************************************
struct formation
{
char blogs;
int n;
struct formation *next;
};
typedef struct
{
struct formation *front;
struct formation *rear;
} linkptr;
//********************************全局变量*************************************
int sockfd = 0;
int numa=0;
int numb=0;
char cmd_buf[20] = {'\0'};
pthread_t pt;
pthread_t ptm;
pthread_mutex_t mut;
linkptr *heada = NULL;
linkptr *headb = NULL;
struct formation *sendp = NULL;
//******************************************************************************
void *pthread_func(void * parg);
struct formation *delp(linkptr *hd);
void pthread_func2(int tfd, char tblg);
void pthread_func1(int tfd, char tblg);
struct formation *greadp(linkptr *hd,char blog,int* num);
//------------------------------------------------------------------------------
//
//队列的建立
//
//------------------------------------------------------------------------------
struct formation *greadp(linkptr *hd,char blog,int *num)
{
struct formation *p1;
p1=(struct formation *)malloc(sizeof(struct formation));
(*num)++;
p1->blogs=blog;
p1->n=*num;
p1->next=NULL;
if (hd->front==NULL)
{
hd->front=p1;
hd->rear=p1;
return (hd->rear);
}
else
{
hd->rear->next=p1;
hd->rear=p1;
return (hd->rear);
}
return (NULL);
}
//---------------------------------------------------------------------------
//
// 队列删除(只在表头)
//
//----------------------------------------------------------------------------
struct formation *delp(linkptr *hd)
{
struct formation *p1 = NULL;
if (hd->front==NULL)
{
p1=(struct formation*)malloc(sizeof(struct formation));
p1->blogs=0;
p1->n=0;
p1->next=NULL;
return (p1);
}
else
{
p1=hd->front;
hd->front=p1->next;
return (p1);
}
}
//----------------------------键盘检测线程函数----------------------------------
//
// 名字: manage_func()
// 功能: 检测键盘是否按下。如果按下键盘检测是否是“exit”
// 是则保存服务器信息。
// 改动: 2007-11-23
//
//----------------------------------------------------------------------
void *manage_func(void *pman)
{
fd_set kbhit;
int select_ret = 0;
while (1)
{
FD_ZERO(&kbhit);
FD_SET(0, &kbhit); // 设置键盘输入进集合
select_ret = select(1, &kbhit, NULL, NULL, NULL);
if ( select_ret <= 0)
{
printf("ERROR!");
}
// 如果 select() 返回大于零的值证明键盘有动作
if (select_ret > 0)
{
scanf("%s", cmd_buf); // 接受键盘输入
if (strcmp(cmd_buf, "exit") == 0)
{
//保存相关信息 退出.
printf("SERVER IS CLOSED!\n");
break;
}
if (strcmp(cmd_buf, "type") == 0)
{
// 显示还有多少用户排队
}
}
}
FD_CLR(0, &kbhit);
while (heada -> front != NULL)
{
struct formation * pt = heada -> front;
heada -> front = heada -> front -> next;
free(pt);
}
while (headb -> front != NULL)
{
struct formation * pt = headb -> front;
headb -> front = headb -> front -> next;
free(pt);
}
free(heada);
free(headb);
close(sockfd);
exit(0);
//pthread_exit(NULL);
return NULL;
}
//----------------有新连开线程------------------------
//
// 名字: void *pthread_func(void *parg)
// 功能: 每次有一个新链接就开新线程.
// void *parg 传入参数为新连接的 socked 字
//
//------------------------------------------------------
void *pthread_func(void *parg)
{
int new_fd = 0;
int numbytes = 0;
char blg = 0;
char buf[MAXDATASIZE];
new_fd = *((int *)parg);
while (1)
{
if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1)
{
perror("recv");
exit(1);
}
buf[numbytes] = 0;
//如果收到的第一个字符是回车就调用叫号机处理函数
if ((int)buf[0]==10)
{
blg=buf[1];
pthread_mutex_lock(&mut);
pthread_func2(new_fd, blg);
pthread_mutex_unlock(&mut);
}
//如果收到的第一个字符时A或者B就调用取好机处理函数
if(buf[0]=='A'||buf[0]=='B')
{
blg=buf[0];
pthread_func1(new_fd, blg);
}
//如果接受到信息为Q 退出循环
if(buf[0] == 'Q')
{
break;
}
}
close(new_fd); // 关闭套接口
pthread_exit(NULL); // 关闭线程
}
//---------------取号机线程函数-------------------------------------------------------
//
// name : void pthread_func1( int tfd, char tblg)
// 参数:tfd 与客户端连接的 socked
// tblg 为此客户端的业务类型
// 功能:根据业务类型 建立相应的节点对列。
// 然后把此节点发送回客户端。
//
//-------------------------------------------------------------------------------------------
void pthread_func1(int tfd, char tblg)
{
if (tblg == 'A')
{
sendp=greadp(heada,tblg,&numa);
}
if (tblg == 'B')
{
sendp=greadp(headb,tblg,&numb);
}
if (send(tfd, sendp, 15, 0) == -1)
{
perror("send");
exit(0);
}
}
//---------------------叫号机线程函数--------------------
//
// name: pthread_func2(int tfd , char tblg);
// 参数: tfd 为与此客户端的 socked
// tblg 为此客户端进行的业务种类
// 功能:取相应对列表头节点发送给客户端
// 然后删除此节点。
//
//--------------------------------------------------------
void pthread_func2(int tfd, char tblg)
{
//buf内容为buf[0]=10;buf[1]=A或者B;此处根据buf[1]内容执行相关队列的删除
if (tblg == 'A')
{
sendp=delp(heada);
if (send(tfd, sendp, 15, 0) == -1)
{
perror("send");
exit(0);
}
free(sendp);
}
if (tblg == 'B')
{
sendp=delp(headb);
if (send(tfd, sendp, 15, 0) == -1)
{
perror("send");
exit(0);
}
free(sendp);
}
}
//-----------------------------程序入口-------------------------------------------
//
//
//
//-----------------------------------------------------------------------------------
int main(int argc, char ** argv)
{
int tempfd = -1;
int new_fd = -1;
struct sockaddr_in my_addr; /* 本机地址信息 */
struct sockaddr_in their_addr; /* 客户地址信息 */
unsigned int sin_size, myport, lisnum;
//*******************************************
heada=(linkptr*)malloc(sizeof(linkptr)); // 初始化A队列头指针
heada->front=heada->rear=NULL;
headb=(linkptr*)malloc(sizeof(linkptr)); // 初始化B队列头指针
headb->front=headb->rear=NULL;
//********************************************
// 建立一个线程用来检测键盘是否按下
if((pthread_create(&ptm,NULL,manage_func,NULL))!=0)
{
printf("Thread Create is Error!\n");
exit(1);
}
if(argv[1])
myport = atoi(argv[1]);
else
myport = 7838;
if(argv[2])
lisnum = atoi(argv[2]);
else
lisnum = 100;
pthread_mutex_init(&mut,NULL);
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
my_addr.sin_family=PF_INET;
my_addr.sin_port=htons(myport);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero), 0);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof (struct sockaddr)) == -1)
{
perror("bind");
exit(1);
}
if (listen(sockfd, lisnum) == -1)
{
perror("listen");
exit(1);
}
printf("SERVER IS RUNING!\n");
// 循环检测是否有新连接进入, 有责开线程处理新连接请求。
while (1)
{
tempfd = -1; // 很关键
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1)
{
perror("accept");
exit(1);
}
// 根据每次来的 new_fd 不同, 为不同连接建立新线程
if(tempfd != new_fd)
{
tempfd = new_fd; // 此处有些无关紧要阿??
if((pthread_create(&pt,NULL,pthread_func,(void*)&new_fd))!=0)
{
printf("Thread Create is Error!\n");
}
}
}
close(sockfd);
//释放A对列内存空间
while (heada -> front != NULL)
{
struct formation * pt = heada -> front;
heada -> front = heada -> front -> next;
free(pt);
}
// 释放B对列内存空间
while (headb -> front != NULL)
{
struct formation * pt = headb -> front;
headb -> front = headb -> front -> next;
free(pt);
}
// 释放对列初始节点
free(heada);
free(headb);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -