You have to implement a ticketing server which is capable of handling numerous clients simultaneously. The server should manage the ticketing procedure and seat position of each client. A client sends queries to the server to get a ticket or a desired seat. A single query represents an action that client can take.
Server
A server takes queries from clients in an infite loop with the following condition.
Client query
아래의 형식을 따르는 하나의 query가 client에서 server로 보내짐
struct query {
int user;
int action;
int data;
}
user -> user id (0 ~ 1023)
action -> action id (1 ~ 5, 0은 terminate)
data -> 각 action에 필요한 data
만약 the user of action field가 range를 벗어난다면, server는 -1 반환
Action in query
5개의 action이 있음
-> Log in
-> Reserve
-> Check reservation
-> Cancel reservation
-> Log out
Response code summary
action과 그에 상응하는 response code들에 대한 table
1, Log in, 1, -1
Termination condition
Client/server examples
06.04
-> multithread server 틀 짜기 완료
남은 거
-> query 조건 다시 확인
-> pthread_mutex 임계 영역 확인
1. If user 1 is currently logged in through client A, every other attempt to log-in as user 1 from the other client must be blocked by the server. And also, the client A cannot send queries of another user before the user 1 successfully log out.
2. When the server receives the query in which all the fields (action, user, data) are zero, server must return the whole integer seat array.
3. The size of the array must be 256 and the value of the array element must be the owner of the corresponding seat. For example, if user 3 successfully reserved seat 14, the value of 14th element in the array should be 3.
4. reserve action에서 seat이 차있으면 ignored. return -1.
-> pthread_mutex 임계 영역 확인
1. user 1이 client A에서 log in 상태이면, 다른 client에서 user 1 로 log in 할 수 없다.
2. user 1이 성공적으로 log out 하기 전까지 client A는 다른 user에서 query를 보낼 수 없다.
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <pthread.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#define SIZE 12
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
struct login{
int log; //login state -1 or 1
int passcode; //passcode
int st; //seat number
};
typedef struct _query {
int user; //0 ~ 1023
int action; //1 ~5, 0 to terminate
int data; //
} query;
struct login l[1024]; //struct array that represent each user state!
int seat[256]; //seat array! seat number range is 0 ~ 255
int ret[2] = {-1, 1}; //simple return value
int clog[1014]; //current login state (for mutex)
void *thread_func(void *arg)
{
int n;
query q;
int connfd = *((int*)arg);
pthread_detach(pthread_self());
free(arg);
while(1){
n = read(connfd, &q, sizeof(q)); //read query
if (q.user == 0 && q.action == 0 && q.data == 0){ //terminate query
write(connfd, seat, sizeof(seat));
break;
}
if (q.action == 1){ //log in 1
if (l[q.user].passcode == -1 && clog[q.user] == 0){ //not been registered
l[q.user].log = 1; //login state set
l[q.user].passcode = q.data; //insert passcode
//pthread_mutex_lock(&mutex);
clog[q.user] = 1;
//pthread_mutex_unlock(&mutex);
printf("log in complete\n");
write(connfd, &ret[1], sizeof(ret[1]));
}
else if (l[q.user].passcode == q.data && clog[q.user] == 0){ //been registered
l[q.user].log = 1; //login state set
//pthread_mutex_lock(&mutex);
clog[q.user] = 1;
//pthread_mutex_unlock(&mutex);
printf("log in complete\n");
write(connfd, &ret[1], sizeof(ret[1]));
}
else{
printf("log in fail\n");
write(connfd, &ret[0], sizeof(ret[0]));
}
continue;
}
else if (q.action == 2){ //reserve 2
if (q.data >= 0 && q.data <=255 && l[q.user].log == 1 && seat[q.data] == -1){
pthread_mutex_lock(&mutex);
seat[q.data] = q.user; //seat <- user id
l[q.user].st = q.data; //also update user state
pthread_mutex_unlock(&mutex);
printf("reserve complete\n");
write(connfd, &q.data, sizeof(q.data));
}
else{
printf("reserve fail\n");
write(connfd, &ret[0], sizeof(ret[0]));
}
continue;
}
else if (q.action == 3){ //check reservation 3
if (l[q.user].log == 1 && l[q.user].st != -1){
printf("check reservation complete\n");
write(connfd, &l[q.user].st, sizeof(l[q.user].st));
}
else{
printf("reserve fail\n");
write(connfd, &ret[0], sizeof(ret[0]));
}
continue;
}
else if (q.action == 4){ //cancel reservation 4
if (l[q.user].log == 1 && seat[q.data] != -1){
pthread_mutex_lock(&mutex);
seat[q.data] = -1;
l[q.user].st = -1;
pthread_mutex_unlock(&mutex);
printf("cancel reservation complete\n");
write(connfd, &q.data, sizeof(q.data));
}
else{
printf("cancel reservation fail\n");
write(connfd, &ret[0], sizeof(ret[0]));
}
continue;
}
else if (q.action == 5){ //log out 5
if (l[q.user].log == 1 && clog[q.user] == 1){
l[q.user].log = -1;
//pthread_mutex_lock(&mutex);
clog[q.user] = 0;
//pthread_mutex_unlock(&mutex);
printf("log out complete\n");
write(connfd, &ret[1], sizeof(ret[1]));
}
else{
printf("log out fail\n");
write(connfd, &ret[0], sizeof(ret[0]));
}
continue;
}
else{
printf("query fail\n");
write(connfd, &ret[0], sizeof(ret[0]));
continue;
}
}
close(connfd);
return NULL;
}
int main(int argc, char *argv[])
{
int n, listenfd, caddrlen, nbytes;
struct sockaddr_in saddr, caddr;
struct hostent *h;
int port = atoi(argv[1]);
if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0){
printf("socket() failed.\n");
exit(1);
} //listen file descriptor (server)
memset((char *)&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(port);
if (bind(listenfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){
printf("bind() failed.\n");
exit(2);
}
if (listen(listenfd, 5) < 0){
printf("listen() failed.\n");
exit(3);
}
for (int i=0; i<256; i++)
seat[i] = -1; //seat initialize
for (int i=0; i<1024; i++){
l[i].log = -1; //user login status initialize
l[i].passcode = -1; //user passcode initialize
l[i].st = -1; //user seat number initialize
clog[i] = 0; //sss initialize 0->login off / 1->login on
}
int *connfdp;
pthread_t tid;
while(1){
connfdp = (int *)malloc(sizeof(int));
caddrlen = sizeof(caddr);
if ((*connfdp = accept(listenfd, (struct sockaddr *)&caddr, (socklen_t *)&caddrlen)) < 0){
printf("accept() failed.\n");
free(connfdp);
continue;
}
printf("wait query ...\n");
pthread_create(&tid, NULL, thread_func, connfdp);
}
pthread_mutex_destroy(&mutex);
free(connfdp);
return 0;
}