⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpserver12.c

📁 目前银行排队机的服务器、打号机、处理窗口三部分的一个基本框架。 程序用多线程、socket编程。
💻 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 + -