global.h
#ifndef _GLOBAL
#define _GLOBAL
//for client
#define QUERY_SINGLE 1
#define QUERY_MULT 2
#define BUY 3
//for server
#define BUY_SUCCEED 128
#define BUY_FAILED 129//need more details for the reason
#define QUERY_SINGLE_SUCCEED 130
#define QUERY_MULT_SUCCEED 131
#define QUERY_SINGLE_FAILED 132//nead more details for the reason
#define QUERY_MULT_FAILED 133//nead...
#define BUFFER_SIZE 65535
#define SERVER_PORT 8888
#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46
struct stMessage
{
unsigned int message_type;//
///if message_type is BUY_FAILED QUERY_SINGLE_FAILED ...
///more struct members should be extent to indicate the detail
unsigned int flight_ID;//
unsigned int ticket_num;//number of tickers
unsigned int ticket_price;//price
unsigned int start_idx;//start index for query mutil data
unsigned int end_idx;//end index for query mutil data
};
#endif
server.c
//server
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include "global.h"
#include "/usr/local/mysql/include/mysql.h"
extern void *pthread_main(void *);
extern void addevent(int,struct kevent *,int);
extern void handleclient(int,struct kevent *);
int main(int argc,char *argv[])
{
//max fd count
long MAX_EVENT_COUNT=sysconf(_SC_OPEN_MAX);
//kqueue
int kq;
//two kevents for listening connection
struct kevent listenchangelist[1],listeneventlist[MAX_EVENT_COUNT];
//file descriptor for listening incoming connection
int listen_fd;
struct sockaddr_in serveraddr;
//create a socket for listening
listen_fd = socket(PF_INET,SOCK_STREAM,0);
if(listen_fd<0)
{
perror(strerror(errno));
return -1;
}
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family = PF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(SERVER_PORT);
//bind to local address
if(bind(listen_fd,(struct sockaddr *)&serveraddr,sizeof(struct sockaddr))<0)
{
perror(strerror(errno));
close(listen_fd);
return -1;
}
//listen
if(listen(listen_fd,10000)<0)
{
perror(strerror(errno));
close(listen_fd);
return -1;
}
//set up kqueue
kq=kqueue();
EV_SET(&listenchangelist[0],listen_fd,EVFILT_READ,EV_ADD,0,0,NULL);
if(kevent(kq,listenchangelist,1,NULL,0,NULL)<0)
{
perror(strerror(errno));
return -1;
}
//start waiting
while(1)
{
printf("kqueue waiting for event...\n");
//return number of events
int count=kevent(kq,NULL,0,listeneventlist,MAX_EVENT_COUNT,NULL);
if(count>0)
{
printf("kevent return: count = :%d.\n",count);
int j;
for(j=0;j < count; ++j)
{
//listening socket fd
if(listeneventlist[j].ident == listen_fd)
addevent(kq,listeneventlist+j,listen_fd);
else//other client socket
handleclient(kq,listeneventlist+j);
}
}
}
return(0);
}
///add new socket to kqueue
void addevent(int kq,struct kevent *kev,int listen_fd)
{
int i;
//on the listen_fd socket
for(i=0;i< kev->data;++i)
{
//accept one connection
int client = accept(listen_fd,NULL,NULL);
//error
if(client < 0)
{
perror(strerror(errno));
continue;
}
//add new socket to kqueue
else
{
struct kevent add_event[1];
EV_SET(&add_event[0],client,EVFILT_READ,EV_ADD|EV_CLEAR,0,0,NULL);
printf("adding new socket EVFILT_READ to kq.\n");
if(kevent(kq,add_event,1,NULL,0,NULL)<0)
{
printf("add new socket to kq error.\n");
perror(strerror(errno));
}
}
}
}
void handleclient(int kq,struct kevent *kev)
{
//socket error
if(kev->flags & EV_EOF||kev->flags & EV_ERROR)
{
struct kevent remove_event[1];
EV_SET(remove_event,kev->ident,EVFILT_READ,EV_DELETE,0,0,NULL);
printf("deleting kevent from kq.\n");
if(kevent(kq,remove_event,1,NULL,0,NULL) < 0)
printf("kevent remove error.socket:%d\n",kev->ident);
//shutdown file descriptor
shutdown(kev->ident,SHUT_RDWR);
//close file descriptor
close(kev->ident);
}
else//thread to read
{
pthread_t tid;
pthread_create(&tid,NULL,pthread_main,(void *)kev->ident);
}
}
void *pthread_main(void *arg)
{
pthread_detach(pthread_self());//detach thread
printf("thread %d started.\n",pthread_self());
struct stMessage msg;//msg
int fd = (int)arg;//socket
char buf[sizeof(struct stMessage)];//buffer for read
if(recv(fd,buf,sizeof(struct stMessage),0)<0)
{
printf("recv error.socket:%d.thread id:%d\n",fd,pthread_self());
return;
}
memcpy(&msg,buf,sizeof(struct stMessage));//copy data to the struct
struct sockaddr_in addr;
socklen_t alenp=sizeof(addr);
getpeername(fd,(struct sockaddr *)&addr,&alenp);//get the address of client
char c_addr[INET_ADDRSTRLEN];
switch(msg.message_type)
{
MYSQL_ROW row;
case QUERY_SINGLE:
printf("Request single from %s:%d.\n",inet_ntop(AF_INET,&addr.sin_addr,c_addr,sizeof(c_addr)),ntohs(addr.sin_port));
if(get_single_record(msg.flight_ID,&row)==1)
{
msg.message_type = QUERY_SINGLE_SUCCEED;
msg.ticket_num = atoi(row[2]);
msg.ticket_price = atoi(row[3]);
}
else
{
msg.message_type = QUERY_SINGLE_FAILED;
}
printf("send single back to client.\n");
if(send(fd,&msg,sizeof(msg),0)<0)
printf("send back to client error.\n");
break;
case QUERY_MULT:
break;
case BUY:
printf("Request buy from %s:%d.\n",inet_ntop(AF_INET,&addr.sin_addr,c_addr,sizeof(c_addr)),ntohs(addr.sin_port));
//buy
msg.message_type = BUY_FAILED;
if(buy_tickets(msg.flight_ID,msg.ticket_num,&row)==1)
{
if(atoi(row[0])==1)
msg.message_type = BUY_SUCCEED;
msg.ticket_price = atoi(row[1]);
}
printf("send buy result back to client.\n");
if(send(fd,&msg,sizeof(msg),0)<0)
printf("send back to client error.\n");
break;
default:
break;
}
printf("thread %d end.\n",pthread_self());
return NULL;
}
///get result from mysql
int get_single_record(int flight_ID,MYSQL_ROW *row)
{
int result = -1;
MYSQL conn;
if(open_mysql(&conn)<0)
{
if(&conn != NULL)//close the MYSQL *
mysql_close(&conn);
return result;
}
char sql[255];
sprintf(sql,"select * from tickets where flight_ID = %d",flight_ID);
/excute the sql
if(mysql_query(&conn,sql)!=0)//return zero if succeed other wise return non-zero
{
printf("excute sql for query error.:%s",mysql_error(&conn));
mysql_close(&conn);
result = -1;
}else//succeed
{
MYSQL_RES *res;
res = mysql_store_result(&conn);
//return non-null and rows of data not zero
if(res != NULL && mysql_num_rows(res) != 0)
{
*row=mysql_fetch_row(res);//get the row
result = 1;
}
mysql_free_result(res);//free the MYSQL_RES *
}
mysql_close(&conn);
return result;
}
int buy_tickets(int flight_ID,int num,MYSQL_ROW *row)
{
int result = -1;
MYSQL conn;
if(open_mysql(&conn)<0)
{
if(&conn != NULL)//close the MYSQL *
mysql_close(&conn);
return result;
}
/*
create procedure buytickets(out result int,out totalprice int, in fid int,in fnum int)
begin
declare dbnum,dbprice int;
set dbnum=0;
set dbprice=0;
set result=-1;
set totalprice=0;
select ticket_num,ticket_price into dbnum,dbprice from tickets
where flight_ID=fid;
if dbnum is not null and dbnum >= fnum then
update tickets set ticket_num=ticket_num-fnum where flight_ID =
fid;
set totalprice=dbprice*fnum;
set result=1;
end if;
end;
*/
char sql[255];
sprintf(sql,"call buytickets(@result,@totalprice,%d,%d)",flight_ID,num);
///mysql_real_query zero returned if successful other wise non-zero
result=mysql_real_query(&conn,sql,(unsigned long)strlen(sql))==0?1:-1;
if(mysql_query(&conn,"select @result,@totalprice")!=0)//return zero if succeed other wise return non-zero
{
printf("excute sql for query error.:%s",mysql_error(&conn));
mysql_close(&conn);
result = -1;
}else//succeed
{
MYSQL_RES *res;
res = mysql_store_result(&conn);
//return non-null and rows of data not zero
if(res != NULL && mysql_num_rows(res) != 0)
{
*row=mysql_fetch_row(res);//get the row
result = 1;
}
mysql_free_result(res);//free the MYSQL_RES *
}
mysql_close(&conn);
return result;
}
///initialize a connection and connect to mysql server
int open_mysql(MYSQL *conn)
{
int result = -1;
if(mysql_init(conn) == NULL)
printf("init connection to mysql error.:%s\n",mysql_error(conn));
else//init ok
{
if(mysql_real_connect(conn,"localhost","pgl","pgl","airp_tickets",0,NULL,0) == NULL)
printf("connect to mysql error.:%s\n",mysql_error(conn));
else//connect ok
result = 1;
}
return result;
}
client.c
//client
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include "global.h"
extern void getresult(int);
int main(int argc,char *argv[])
{
int socket_fd;
socket_fd = socket(PF_INET,SOCK_STREAM,0);
if(socket_fd < 0)
{
printf("create socket error.\n");
return -1;
}
if(argc != 2)
return 0;
struct sockaddr_in server;
server.sin_family=PF_INET;
// server.sin_addr.s_addr=inet_addr(argc == 2 ? argv[1]:"127.0.0.1");
server.sin_addr.s_addr = inet_addr(argv[1]);
server.sin_port=htons(SERVER_PORT);
printf("connecting to server...\n");
if(connect(socket_fd,(struct sockaddr*)&server,sizeof(server))<0)
{
printf("connect to server error.\n");
close(socket_fd);
return -1;
}
printf("connect to server successful.\n");
char c[10];
do
{
printf("input cmd(char) ...\n");
if(scanf("%s",c) == 0)
continue;
if(c[0] == '\r'||c[0] =='\n')
continue;
if(c[0] == 'q'||c[0] == 'Q')
break;
switch(c[0])
{
case 'B':
if(buy_tickets(socket_fd))
// getresult(socket_fd);
break;
case 'G':
if(inquire_tickets(socket_fd))
getresult(socket_fd);
break;
default:break;
}
}while(1);
shutdown(socket_fd,SHUT_RDWR);
close(socket_fd);
return(0);
}
int buy_tickets(int socket_fd)
{
struct stMessage msg;
printf("buy tickets.input flight id:\n");
if(scanf("%d",&msg.flight_ID))//input flight id
{
printf("how many tickets do you want to buy:");
if(scanf("%d",&msg.ticket_num))
{
msg.message_type = BUY;//message type
printf("send buy stMessage to server...\n");
if(send(socket_fd,&msg,sizeof(msg),0) < 0)
{
printf("send stMessage to server error.\n");
return -1;
}
}
else
{
printf("input ticket num error.\n");
return -1;
}
}
else
{
printf("input flight id error.\n");
return -1;
}
return 1;
}
int inquire_tickets(int socket_fd)
{
struct stMessage msg;
printf("query tickets.input flight id:\n");
if(scanf("%d",&msg.flight_ID))//input flight id
{
msg.message_type = QUERY_SINGLE;//message type
printf("send query stMessage to server...\n");
if(send(socket_fd,&msg,sizeof(msg),0) < 0)
{
printf("send stMessage to server error.\n");
return -1;
}
}
else
{
printf("input flight id error.\n");
return -1;
}
return 1;
}
void getresult(int socket_fd)
{
struct stMessage msg;
char buf[sizeof(struct stMessage)];
printf("receiving stMessage...\n");
if(recv(socket_fd,buf,sizeof(struct stMessage),0)<0)
printf("recv from server error.\n");
memcpy(&msg,buf,sizeof(struct stMessage));
switch(msg.message_type)
{
case BUY_SUCCEED:
printf("Buy tickets succeed.\n");
break;
case BUY_FAILED:
printf("Buy tickets failed.\n");
break;
case QUERY_SINGLE_SUCCEED:
printf("flight:%d,num:%d,price:%d\n",msg.flight_ID,msg.ticket_num,msg.ticket_price);
break;
case QUERY_MULT_SUCCEED:
break;
case QUERY_SINGLE_FAILED:
printf("Inquire single ticket failed.\n");
break;
case QUERY_MULT_FAILED:
break;
default:break;
}
}
exe=./exe/
RM=rm -f
MYSQLLIB=/usr/local/mysql/lib
target:server client
server:server.c
gcc -g -lpthread -lmysqlclient -L$(MYSQLLIB) server.c -o $(exe)server 2>log
client:client.c
gcc -g client.c -o $(exe)client 2>log
clean:
$(RM) *.o *.core *.out $(exe)* log
exec:
mkdir -p ./exe;