航空售票例子之服务器端的线程设计

服务器端在监听客户端的请求采用了一个线程,在为每个客户请求时又安排了一个线程。

下面是用来监听客户端请求的线程所执行的函数:

int listen_fd,conn_fd;     //监听socket,连接socket
struct sockaddr_in server,cli_addr;
int ret,buffer_index,i,cli_len;
unsigned long ip_addr;
int flag = 1;
pthread_t listentid,servicetid;     //监听线程ID,服务线程ID

/*监听线程*/
void* listen_thread(void *p)
{
	char msg[512];
	while(1){
		/*接受远端的TCP连接请求*/
		cli_len = sizeof(cli_addr);
		conn_fd = accept(listen_fd,(struct sockaddr *)&cli_addr,&cli_len);
		if(conn_fd<0)
			continue;

		ip_addr = ntohl(cli_addr.sin_addr.s_addr);
		/*检测重复连接*/
		check_connection(ip_addr);
		/*分配线程缓冲区*/
		buffer_index = get_free_buff();
		if(buffer_index<0){
			sprintf(msg,"没用空闲的线程缓冲区。\n");
			add_info(msg);
			close(conn_fd);
			continue;
		}
		/*填写服务线程需要的信息*/
		pthread_mutex_lock(&buff_mutex);
		thread_buff[buffer_index].buff_index = buffer_index;
		thread_buff[buffer_index].ip_addr = ip_addr;
		thread_buff[buffer_index].conn_fd = conn_fd;
		thread_buff[buffer_index].buff_status = BUFF_OCCUPIED;
		pthread_mutex_unlock(&buff_mutex);

		/*创建新底服务线程*/
		ret = pthread_create(&servicetid,NULL,service_thread,&thread_buff[buffer_index]);
		if(ret == -1){
			sprintf(msg,"创建服务器线程出错!\n");
			add_info(msg);
			close(conn_fd);
			/*释放线程缓冲区*/
			pthread_mutex_lock(&buff_mutex);
			thread_buff[buffer_index].tid = 0;
			thread_buff[buffer_index].buff_status = BUFF_FREED;
			pthread_mutex_unlock(&buff_mutex);
		}
	}
}
为客户端安排的服务线程调用的函数是:void* service_thread(void *p)

#ifndef _SERVICE_THREAD_H
#define _SERVICE_THREAD_H

#include "ticket.h"
#include "threadbuff.h"

static void thread_err(char *s, int index)
{
	int i;
	char msg[512];
	sprintf(msg,"线程%d发生致命错误:%s\n",(unsigned int)pthread_self(),s);
	add_info(msg);
	free_buff(index);
	pthread_exit(NULL);
}

void* service_thread(void *p)
{
	int conn_fd;
	/*线程缓冲区标号*/
	int buff_index;
	char send_buf[1024],recv_buf[512];
	int ret,i,cnt;
	uint16_t nbyte;
	struct sockaddr_in peer_name;
	int peer_name_len;
	unsigned int required_ticket_num;
	int pos;
	thread_buff_struct *pstruct;
	char msg[512];
	/*获取线程使用底线程缓冲区的序号*/
	pstruct = (thread_buff_struct *)p;
	buff_index = pstruct->buff_index;

	/*从线程缓冲区中获取通信使用底套接子描述符,通过accept获取*/
	conn_fd = pstruct->conn_fd;

	/*打印远程主机地址*/
	peer_name_len = sizeof(peer_name);
	ret = getpeername(conn_fd,(struct sockaddr*)&peer_name,&peer_name_len);
	if(ret==-1)
		thread_err("获取远端主机地址出错",buff_index);

	sprintf(msg,"新链接--->线程ID:%d,接连ID:%d,线程缓冲区索引号:%d,远端地址:%s,端口号:%d\n", (unsigned short)pstruct->tid,conn_fd,buff_index,inet_ntoa(peer_name.sin_addr),ntohs(peer_name.sin_port));
	add_info(msg);
	while(1){
		/*从网络中获取数据记录*/
		ret = recv(conn_fd,recv_buf,sizeof(message),0);
		/*接受出错*/
		if(ret == -1){
			sprintf(msg,"线程:%d 在链接:%d接收出错。链接将关闭\n",(unsigned short)pstruct->tid, conn_fd);
			add_info(msg);
			thread_err(msg, buff_index);
		}
		/*ret==0说明客户端链接已关闭*/
		if(ret == 0){
			sprintf(msg,"线程 %d 的链接(ID:%d) 客户端已关闭。服务器端链接也将关闭。\n",(unsigned short)pstruct->tid,conn_fd);
			add_info(msg);
			close(conn_fd);
			free_buff(buff_index);
			pthread_exit(NULL);
		}
		/*ret为其他值说明接受到了客户端底请求消息*/
		init_message();
		memcpy(&message,recv_buf,sizeof(message));
		switch(message.msg_type){
			case DISCONNECT:
				sprintf(msg,"线程 %d 的链接(ID: %d)客户端已关闭。服务器链接也将关闭。\n",(unsigned short)pstruct->tid,conn_fd);
				add_info(msg);
				close(conn_fd);
				free_buff(buff_index);
				pthread_exit(NULL);
				break;
			case BUY_TICKET:
				for(i=0;i<FLIGHT_NUM;i++){
					pthread_mutex_lock(&ticket_list[i].ticket_mutex);
					if(ticket_list[i].flight_ID == message.flight_ID){
						if(ticket_list[i].ticket_num >= message.ticket_num){
							//剩余票数大于请求票数
							message.msg_type = BUY_SUCCEED;
							message.ticket_total_price=message.ticket_num*ticket_list[i].ticket_price;
							ticket_list[i].ticket_num -= message.ticket_num;
							pthread_mutex_unlock(&ticket_list[i].ticket_mutex);
							sprintf(msg,"购买成功!航班号:%d,票数:%d,总票价:%d\n",message.flight_ID,message.ticket_num,message.ticket_total_price);
							add_info(msg);
							memcpy(send_buf,&message,sizeof(message));
							ret = send(conn_fd,send_buf,sizeof(message),0);
							if(ret<0)
								thread_err("发送数据出错\n",buff_index);
							break;
						}else{
							//剩余票数不足,购买失败
							message.msg_type = BUY_FAILED;
							required_ticket_num = message.ticket_num;
							message.ticket_num = ticket_list[i].ticket_num;
							pthread_mutex_unlock(&ticket_list[i].ticket_mutex);
							sprintf(msg,"购买失败!航班号:%d,剩余票数:%d,请求票数:%d\n",message.flight_ID,message.ticket_num,required_ticket_num);
							add_info(msg);
							memcpy(send_buf,&message,sizeof(message));
							ret=send(conn_fd,send_buf,sizeof(message),0);
							if(ret<0)
								thread_err("发送数据出错\n",buff_index);
							break;
						}

					}
					pthread_mutex_unlock(&ticket_list[i].ticket_mutex);
				}
				break;

            case INQUIRE_ONE:
                for(i=0;i<FLIGHT_NUM;i++){
                    pthread_mutex_lock(&ticket_list[i].ticket_mutex);
                    if(ticket_list[i].flight_ID == message.flight_ID){
                        message.msg_type = INQUIRE_SUCCEED;
                        message.ticket_num = ticket_list[i].ticket_num;
                        message.ticket_total_price = ticket_list[i].ticket_price;
                        pthread_mutex_unlock(&ticket_list[i].ticket_mutex);
                        printf("查询成功!航班号:%d,票数:%d,票价:%d\n",message.flight_ID,message.ticket_num,message.ticket_total_price);
                        sprintf(msg,"查询成功!航班号:%d,票数:%d,票价:%d\n",message.flight_ID,message.ticket_num,message.ticket_total_price);
                        add_info(msg);
                        memcpy(send_buf,&message,sizeof(message));
                        ret = send(conn_fd,send_buf,sizeof(message),0);
                        if(ret<0)
                            thread_err("发送数据出错\n",buff_index);
                        break;
                    }
                    pthread_mutex_unlock(&ticket_list[i].ticket_mutex);
                }
                break;

            case INQUIRE_ALL:
                pos = 0;

                for(i=0;i<FLIGHT_NUM;i++){
                    pthread_mutex_lock(&ticket_list[i].ticket_mutex);
                    message.msg_type = INQUIRE_SUCCEED;
                    message.flight_ID = ticket_list[i].flight_ID;
                    message.ticket_num = ticket_list[i].ticket_num;
                    message.ticket_total_price = ticket_list[i].ticket_price;
                    pthread_mutex_unlock(&ticket_list[i].ticket_mutex);
                    /*经过一圈又回来了*/
                    if(i==0){
                        sprintf(msg,"查询所有航班号成功!\n");
                        add_info(msg);
                    }
                    sprintf(msg,"航班号:%d,票数:%d,票价:%d\n",message.flight_ID,message.ticket_num,message.ticket_total_price);
                    add_info(msg);
                    memcpy(send_buf+pos,&message,sizeof(message));
                    pos+=sizeof(message);
                }
                ret = send(conn_fd,send_buf,pos,0);

                if(ret<0)
                    thread_err("发送数据出错\n",buff_index);
                break;

            default:

                message.msg_type = UNKNOWN_CODE;
                memcpy(send_buf,&message,sizeof(message));
                ret=send(conn_fd,send_buf,sizeof(message),0);
                if(ret<0)
                    thread_err("发送数据出错\n",buff_index);

		}
	}
}


#endif



项目代码下载地址: 航空售票项目源码。有一些小BUG,还在继续改进。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值