diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9cd751f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cstdio": "c" + } +} \ No newline at end of file diff --git a/LICENSE b/LICENSE index ff183c0..e854f82 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2021 源文雨 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2021 源文雨 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index b1ffea3..a70487c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# simple-dict-server -database["key"]="value" +# simple-dict-server +database["key"]="value" diff --git a/client b/client new file mode 100644 index 0000000..6051e6e Binary files /dev/null and b/client differ diff --git a/client.c b/client.c new file mode 100644 index 0000000..03a1307 --- /dev/null +++ b/client.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc,char *argv[]) { + int sockfd, numbytes; + char buf[BUFSIZ]; + struct sockaddr_in their_addr; + puts("break!"); + while((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1); + puts("Get sockfd"); + their_addr.sin_family = AF_INET; + their_addr.sin_port = htons(8000); + their_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); + bzero(&(their_addr.sin_zero), 8); + + while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1); + puts("Connected to server"); + 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); + } + close(sockfd); + return 0; +} diff --git a/server b/server new file mode 100644 index 0000000..5a32184 Binary files /dev/null and b/server differ diff --git a/server.c b/server.c new file mode 100644 index 0000000..f1d2450 --- /dev/null +++ b/server.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int fd, accept_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]; +FILE *fp = NULL; + +struct DICTBLK{ + char key[255]; + u_char keysize; + char data[255]; + u_char datasize; +}; +typedef struct DICTBLK DICTBLK; +#define DICTBLKSZ sizeof(DICTBLK) +DICTBLK dict; + +#define showUsage(program) printf("Usage: %s listen_port try_times dict_file\n", program) + +int bindServer(uint16_t port, u_int try_times) { + int fail_count = 0; + int result = -1; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + server_addr.sin_addr.s_addr = INADDR_ANY; + bzero(&(server_addr.sin_zero), 8); + + fd = socket(AF_INET, SOCK_STREAM, 0); + while(!~(result = bind(fd, (struct sockaddr *)&server_addr, struct_len)) && fail_count++ < try_times) sleep(1); + if(!~result && fail_count >= try_times) { + perror("Bind server failure!"); + return 0; + } else{ + puts("Bind server success!"); + return 1; + } +} + +int listenSocket(u_int try_times) { + int fail_count = 0; + int result = -1; + while(!~(result = listen(fd, 10)) && fail_count++ < try_times) sleep(1); + if(!~result && fail_count >= try_times) { + perror("Listen failed!"); + return 0; + } else{ + puts("Listening...."); + return 1; + } +} + +int sendData(char *data, size_t length) { + if(send(accept_fd, data, length, 0) < 0) { + perror("Send data error"); + return 0; + } else { + printf("Send data: "); + while(length--) putchar(*data++); + putchar('\n'); + return 1; + } +} + +int s0_init(int *s) { + if(!strcmp("get", buff)) *s = 1; + else if(!strcmp("set", buff)) *s = 2; + else if(!strcmp("del", buff)) *s = 4; + else if(!strcmp("quit", buff)) return 0; + return sendData(buff, numbytes); +} + +int s1_get(int *s) { + rewind(fp); + while(fread(&dict, DICTBLKSZ, 1, fp) > 0) { + u_char ks = dict.keysize; + dict.key[ks] = 0; + printf("[%s] Look key: (%d)%s\n", buff, ks, dict.key); + if(!strcmp(buff, dict.key)) { + *s = 0; + return sendData(dict.data, dict.datasize); + } + } + *s = 0; + return sendData("null", 4); +} + +#define copyKey() {\ + dict.keysize = (numbytes >= 255)?255:numbytes;\ + strncpy(dict.key, buff, 255);\ +} + +int s2_set(int *s) { + rewind(fp); + *s = 3; + while(fread(&dict, DICTBLKSZ, 1, fp) > 0) { + u_char ks = dict.keysize; + dict.key[ks] = 0; + printf("[%ld] Key size: %d\n", numbytes, ks); + if(!dict.keysize || !strcmp(buff, dict.key)) { + copyKey(); + fseek(fp, -DICTBLKSZ, SEEK_CUR); + return sendData("data", 4); + } + } + copyKey(); + fseek(fp, 0, SEEK_END); + return sendData("data", 4); +} + +int s3_setData(int *s) { + dict.datasize = (numbytes >= 255)?255: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); + } else { + printf("Set data: dict[%s]=%s\n", dict.key, buff); + fflush(fp); + return sendData("succ", 4); + } +} + +int s4_del(int *s) { + rewind(fp); + *s = 0; + while(fread(&dict, DICTBLKSZ, 1, fp) > 0) { + dict.key[dict.keysize] = 0; + if(!strcmp(buff, dict.key)) { + fseek(fp, -DICTBLKSZ+255, SEEK_CUR); + fputc(0, fp); + return sendData("succ", 4); + } + } + return sendData("null", 4); +} + +int checkBuffer() { + 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; + default: return -1; break; + } +} + +void acceptClient() { + puts("Ready for accept, waitting..."); + accept_fd = accept(fd, (struct sockaddr *)&client_addr, &struct_len); + if(accept_fd > 0) { + puts("Connected to the client."); + sendData("Welcome to simple dict server.", 31); + while((numbytes = recv(accept_fd, buff, BUFSIZ, 0)) > 0) { + buff[numbytes] = 0; + printf("Get %ld bytes: %s\n", numbytes, buff); + puts("Check buffer"); + if(!checkBuffer()) break; + } + fprintf(stderr, "Recv %ld bytes\n", numbytes); + close(accept_fd); + } else perror("Error accepting client"); +} + +int main(int argc, char *argv[]) { + if(argc != 4) showUsage(argv[0]); + else { + int port = 0; + sscanf(argv[1], "%d", &port); + if(port > 0 && port < 65536) { + int times = 0; + sscanf(argv[2], "%d", ×); + if(times > 0) { + fp = NULL; + fp = fopen(argv[3], "rb+"); + if(!fp) fp = fopen(argv[3], "wb+"); + if(fp) { + if(bindServer(port, times)) if(listenSocket(times)) while(1) acceptClient(); + } else fprintf(stderr, "Error opening dict file: %s\n", argv[3]); + } else fprintf(stderr, "Error times: %d\n", times); + } else fprintf(stderr, "Error port: %d\n", port); + } + close(fd); + exit(EXIT_FAILURE); +}