diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1899660 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build +.vscode \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b726dd1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,13 @@ +project(simple-dict-server) +add_executable(simple-dict-server server.c) # 生成可执行文件 +add_executable(simple-dict-client client.c) # 生成可执行文件 +target_link_libraries( # 目标库 + simple-dict-server + + # 目标库需要链接的库 + pthread) +target_link_libraries( # 目标库 + simple-dict-client + + # 目标库需要链接的库 + pthread) diff --git a/client b/client deleted file mode 100644 index 57b37f9..0000000 Binary files a/client and /dev/null differ diff --git a/client.c b/client.c index 9e30e95..40e638b 100644 --- a/client.c +++ b/client.c @@ -7,11 +7,25 @@ #include #include #include +#include + +int sockfd; +char buf[BUFSIZ]; +char bufr[BUFSIZ]; +struct sockaddr_in their_addr; +pthread_t thread; + +void getMessage(void *p) { + int c = 0; + while((c = recv(sockfd, bufr, BUFSIZ, 0)) > 0) { + printf("Recv %d bytes: ", c); + for(int i = 0; i < c; i++) putchar(bufr[i]); + putchar('\n'); + } +} int main(int argc,char *argv[]) { //usage: ./client host port - int sockfd, numbytes; - char buf[BUFSIZ]; - struct sockaddr_in their_addr; + ssize_t numbytes; puts("break!"); while((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1); puts("Get sockfd"); @@ -25,14 +39,15 @@ int main(int argc,char *argv[]) { //usage: ./client host port numbytes = recv(sockfd, buf, BUFSIZ,0); buf[numbytes]='\0'; puts(buf); - while(1) { - printf("Enter command:"); - scanf("%s",buf); - numbytes = send(sockfd, buf, strlen(buf), 0); - numbytes = recv(sockfd,buf,BUFSIZ,0); - buf[numbytes]='\0'; - puts(buf); - } + if(!pthread_create(&thread, NULL, (void*)&getMessage, NULL)) { + puts("Thread create succeeded"); + while(1) { + printf("Enter command:"); + scanf("%s",buf); + numbytes = send(sockfd, buf, strlen(buf), 0); + sleep(1); + } + } else perror("Create msg thread failed"); close(sockfd); return 0; } diff --git a/server b/server deleted file mode 100644 index cc23361..0000000 Binary files a/server and /dev/null differ diff --git a/server.c b/server.c index fce3df2..4359a90 100644 --- a/server.c +++ b/server.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -9,16 +10,26 @@ #include #include #include +#include +#include -int fd, accept_fd; +int fd; ssize_t numbytes; socklen_t struct_len = sizeof(struct sockaddr_in); struct sockaddr_in server_addr; struct sockaddr_in client_addr; char buff[BUFSIZ]; -char buff2[BUFSIZ]; FILE *fp = NULL; char *file_path; +pthread_t accept_threads[8]; + +#define MAXWAITSEC 10 +struct THREADTIMER { + pthread_t *thread; + time_t touch; + int accept_fd; +}; +typedef struct THREADTIMER THREADTIMER; #define DATASIZE 64 struct DICTBLK{ @@ -34,17 +45,21 @@ DICTBLK dict; #define showUsage(program) printf("Usage: %s [-d] listen_port try_times dict_file\n\t-d: As daemon\n", program) void acceptClient(); +void acceptTimer(void *p); int bindServer(uint16_t port, u_int try_times); -int checkBuffer(); +int checkBuffer(int accept_fd); off_t fileSize(const char* fname); +void handleAccept(void *accept_fd_p); +void handle_quit(int signo); int listenSocket(u_int try_times); -int sendData(char *data, size_t length); -int s0_init(int *s); -int s1_get(int *s); -int s2_set(int *s); -int s3_setData(int *s); -int s4_del(int *s); -int s5_list(int *s); +int sendAll(int accept_fd); +int sendData(int accept_fd, char *data, size_t length); +int s0_init(int *s, int accept_fd); +int s1_get(int *s, int accept_fd); +int s2_set(int *s, int accept_fd); +int s3_setData(int *s, int accept_fd); +int s4_del(int *s, int accept_fd); +int s5_list(int *s, int accept_fd); int bindServer(uint16_t port, u_int try_times) { int fail_count = 0; @@ -78,7 +93,7 @@ int listenSocket(u_int try_times) { } } -int sendData(char *data, size_t length) { +int sendData(int accept_fd, char *data, size_t length) { if(send(accept_fd, data, length, 0) < 0) { perror("Send data error"); return 0; @@ -90,16 +105,28 @@ int sendData(char *data, size_t length) { } } -int s0_init(int *s) { +int sendAll(int accept_fd) { + int re = 1; + rewind(fp); + sprintf(buff, "%zd", fileSize(file_path)); + re = sendData(accept_fd, buff, strlen(buff)); + while((numbytes = fread(buff, 1, BUFSIZ, fp)) > 0) { + re = sendData(accept_fd, buff, numbytes); + } + return re; +} + +int s0_init(int *s, int accept_fd) { if(!strcmp("get", buff)) *s = 1; else if(!strcmp("set", buff)) *s = 2; else if(!strcmp("del", buff)) *s = 4; else if(!strcmp("lst", buff)) *s = 5; + else if(!strcmp("cat", buff)) return sendAll(accept_fd); else if(!strcmp("quit", buff)) return 0; - return sendData(buff, numbytes); + return sendData(accept_fd, buff, numbytes); } -int s1_get(int *s) { +int s1_get(int *s, int accept_fd) { rewind(fp); while(fread(&dict, DICTBLKSZ, 1, fp) > 0) { u_char ks = dict.keysize; @@ -107,11 +134,11 @@ int s1_get(int *s) { printf("[%s] Look key: (%d)%s\n", buff, ks, dict.key); if(!strcmp(buff, dict.key)) { *s = 0; - return sendData(dict.data, dict.datasize); + return sendData(accept_fd, dict.data, dict.datasize); } } *s = 0; - return sendData("null", 4); + return sendData(accept_fd, "null", 4); } #define copyKey() {\ @@ -119,7 +146,7 @@ int s1_get(int *s) { strncpy(dict.key, buff, (DATASIZE-1));\ } -int s2_set(int *s) { +int s2_set(int *s, int accept_fd) { rewind(fp); *s = 3; while(fread(&dict, DICTBLKSZ, 1, fp) > 0) { @@ -129,29 +156,29 @@ int s2_set(int *s) { if(!dict.keysize || !strcmp(buff, dict.key)) { copyKey(); fseek(fp, -DICTBLKSZ, SEEK_CUR); - return sendData("data", 4); + return sendData(accept_fd, "data", 4); } } copyKey(); fseek(fp, 0, SEEK_END); - return sendData("data", 4); + return sendData(accept_fd, "data", 4); } -int s3_setData(int *s) { +int s3_setData(int *s, int accept_fd) { dict.datasize = (numbytes >= (DATASIZE-1))?(DATASIZE-1):numbytes; memcpy(dict.data, buff, dict.datasize); *s = 0; if(fwrite(&dict, DICTBLKSZ, 1, fp) != 1) { fprintf(stderr, "Error set data: dict[%s]=%s\n", dict.key, buff); - return sendData("erro", 4); + return sendData(accept_fd, "erro", 4); } else { printf("Set data: dict[%s]=%s\n", dict.key, buff); fflush(fp); - return sendData("succ", 4); + return sendData(accept_fd, "succ", 4); } } -int s4_del(int *s) { +int s4_del(int *s, int accept_fd) { rewind(fp); *s = 0; while(fread(&dict, DICTBLKSZ, 1, fp) > 0) { @@ -159,10 +186,10 @@ int s4_del(int *s) { if(!strcmp(buff, dict.key)) { fseek(fp, -DICTBLKSZ+(DATASIZE-1), SEEK_CUR); fputc(0, fp); - return sendData("succ", 4); + return sendData(accept_fd, "succ", 4); } } - return sendData("null", 4); + return sendData(accept_fd, "null", 4); } off_t fileSize(const char* fname) { @@ -171,7 +198,7 @@ off_t fileSize(const char* fname) { else return -1; } -int s5_list(int *s) { +int s5_list(int *s, int accept_fd) { *s = 0; off_t size = fileSize(file_path) / DICTBLKSZ; char *keys = calloc(size, DATASIZE); @@ -188,42 +215,85 @@ int s5_list(int *s) { } } int len = strlen(keys); - if(len > 0) return sendData(keys, len); - else return sendData("null", 4); - } else return sendData("erro", 4); + if(len > 0) return sendData(accept_fd, keys, len); + else return sendData(accept_fd, "null", 4); + } else return sendData(accept_fd, "erro", 4); } -int checkBuffer() { +int checkBuffer(int accept_fd) { static int s = 0; printf("Status: %d\n", s); switch(s) { - case 0: return s0_init(&s); break; - case 1: return s1_get(&s); break; - case 2: return s2_set(&s); break; - case 3: return s3_setData(&s); break; - case 4: return s4_del(&s); break; - case 5: return s5_list(&s); break; + case 0: return s0_init(&s, accept_fd); break; + case 1: return s1_get(&s, accept_fd); break; + case 2: return s2_set(&s, accept_fd); break; + case 3: return s3_setData(&s, accept_fd); break; + case 4: return s4_del(&s, accept_fd); break; + case 5: return s5_list(&s, accept_fd); break; default: return -1; break; } } -void acceptClient() { - puts("Ready for accept, waitting..."); - accept_fd = accept(fd, (struct sockaddr *)&client_addr, &struct_len); +void handle_quit(int signo) { + printf("Handle sig %d\n", signo); + pthread_exit(NULL); +} + +void acceptTimer(void *p) { + THREADTIMER *timer = (THREADTIMER*)p; + while(!pthread_kill(*(timer->thread), 0)) { + sleep(MAXWAITSEC); + puts("Check accept status"); + if(time(NULL) - timer->touch > MAXWAITSEC) { + pthread_kill(*(timer->thread), SIGQUIT); + close(timer->accept_fd); + } + } + free(p); +} + +#define touchTimer(x) ((THREADTIMER*)(x))->touch = time(NULL) + +void handleAccept(void *p) { + int accept_fd = ((THREADTIMER*)p)->accept_fd; if(accept_fd > 0) { puts("Connected to the client."); - sendData("Welcome to simple dict server.", 31); + signal(SIGQUIT, handle_quit); + pthread_t thread; + if (pthread_create(&thread, NULL, (void *)&acceptTimer, p)) perror("Error creating timer thread"); + else puts("Creating timer thread succeeded"); + sendData(accept_fd, "Welcome to simple dict server.", 31); while((numbytes = recv(accept_fd, buff, BUFSIZ, 0)) > 0) { + touchTimer(p); buff[numbytes] = 0; printf("Get %zd bytes: %s\n", numbytes, buff); puts("Check buffer"); - if(!checkBuffer()) break; + if(!checkBuffer(accept_fd)) break; } fprintf(stderr, "Recv %zd bytes\n", numbytes); close(accept_fd); } else perror("Error accepting client"); } +void acceptClient() { + while(1) { + puts("Ready for accept, waitting..."); + int p = 0; + while(p < 8 && accept_threads[p] && !pthread_kill(accept_threads[p], 0)) p++; + if(p < 8) { + THREADTIMER *timer = malloc(sizeof(THREADTIMER)); + timer->accept_fd = accept(fd, (struct sockaddr *)&client_addr, &struct_len); + timer->thread = &accept_threads[p]; + timer->touch = time(NULL); + if (pthread_create(timer->thread, NULL, (void *)&handleAccept, timer)) perror("Error creating thread"); + else puts("Creating thread succeeded"); + } else { + puts("Max thread cnt exceeded"); + sleep(1); + } + } +} + int main(int argc, char *argv[]) { if(argc != 4 && argc != 5) showUsage(argv[0]); else { @@ -240,7 +310,7 @@ int main(int argc, char *argv[]) { if(!fp) fp = fopen(argv[as_daemon?4:3], "wb+"); if(fp) { file_path = argv[as_daemon?4:3]; - if(bindServer(port, times)) if(listenSocket(times)) while(1) acceptClient(); + if(bindServer(port, times)) if(listenSocket(times)) acceptClient(); } else fprintf(stderr, "Error opening dict file: %s\n", argv[as_daemon?4:3]); } else perror("Start daemon error"); } else fprintf(stderr, "Error times: %d\n", times);