📄 pppserv.c
字号:
#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <arpa/inet.h>#include <errno.h>#define RIO_BUFSIZE 8192#define LISTENQ 1024#define MAXLINE 8192#define FALSE 0#define TRUE 1#define DATABASE 200typedef struct sockaddr SA;typedef struct { int rio_fd; /* descriptor for this internal buf */ int rio_cnt; /* unread bytes in internal buf */ char *rio_bufptr; /* next unread byte in internal buf */ char rio_buf[RIO_BUFSIZE]; /* internal buffer */} rio_t;/* * The in-memory database which stores * all the file entry information */typedef struct { char *title; char *host_name; int port; int valid;} file_entry;/* do the register request from client */int register_file(int connfd, rio_t* riop);/* do the add file request from client */int add_file(int connfd, rio_t* rio);/* do the deregister request from client */int deregister_file(int connfd, rio_t* riop);/* check the file entry in the in-memory database */int check_in_database(char *title, char* host, int port);/* do the query request from client */void query(int connfd, rio_t* riop);/* increment the entry index */void incre(int entry);/* Print the in-memory database (debug) */void print_database();/* The Rio package - robust I/O functions */ssize_t rio_readn(int fd, void *usrbuf, size_t n);ssize_t rio_writen(int fd, void *usrbuf, size_t n);void rio_readinitb(rio_t *rp, int fd); ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);/* The in-memory database */file_entry database[DATABASE];/* The available database entry */int ava_entry = 0;int main(int argc, char **argv){ int port, listenfd, clientlen, connfd; struct sockaddr_in clientaddr; int i; if (argc != 2 ) { printf("usage: %s <port>\n", argv[0]); exit(1); } // Clean the database for (i = 0; i < DATABASE; i++) { database[i].valid = FALSE; } port = atoi(argv[1]); listenfd = open_listenfd(port); while(1) { clientlen = sizeof(clientaddr); connfd = accept(listenfd, (SA *)&clientaddr, &clientlen); printf("Server connected to a client.\n"); size_t n; char buf[MAXLINE]; rio_t rio; rio_readinitb(&rio, connfd); while((n = rio_readlineb(&rio, buf, MAXLINE)) != 0) { rio_writen(connfd, buf, n); if (strcmp(buf, "REGISTER\n") == 0) { register_file(connfd, &rio); break; } else if((strcmp(buf, "ADD ENTRY\n") == 0)) { add_file(connfd, &rio); break; } else if((strcmp(buf, "DEREGISTER\n") == 0)) { deregister_file(connfd, &rio); break; } else if((strcmp(buf, "QUERY\n") == 0)) { // Fork the child to do the query if (fork() == 0) { close(listenfd); query(connfd,&rio); close(connfd); exit(0); } break; } } printf("Server closes the current connection.\n"); printf("Server is waiting for the next connection.\n"); close(connfd); } exit(0); }/* * Register the file entries sent by client. */int register_file(int connfd, rio_t* riop){ size_t n; char buf[MAXLINE]; char* token, *token1; int i; while((n = rio_readlineb(riop, buf, MAXLINE)) != 0) { if (strcmp(buf, ".\n") == 0) { rio_writen(connfd, "SUCCESS\n", 8); rio_readlineb(riop, buf, MAXLINE); fflush(stdout); break; } token = strchr(buf, ':'); token[0] = '\0'; token++; token1 = strchr(token, ':'); token1[0] = '\0'; token1++; token1[strlen(token1)-1] = '\0'; // The same entry is in the database alreaedy. if (check_in_database(buf, token, atoi(token1))) { rio_writen(connfd,"in database\n",12); continue; } i = 0; while(buf[i]) { buf[i] = tolower(buf[i]); i++; } // Store the entry to the in-memory database database[ava_entry].title = (char *)malloc(strlen(buf)+1); strcpy(database[ava_entry].title, buf); database[ava_entry].host_name = (char *)malloc(strlen(token)+1); strcpy(database[ava_entry].host_name, token); database[ava_entry].port = atoi(token1); database[ava_entry].valid = TRUE; incre(ava_entry); rio_writen(connfd,"added\n",6); } return TRUE;}/* * Add the file entry to the database. */int add_file(int connfd, rio_t* riop){ size_t n; char buf[MAXLINE]; char *token, *token1; while((n = rio_readlineb(riop, buf, MAXLINE)) != 0) { if (strcmp(buf, ".\n") == 0) { rio_writen(connfd, "SUCCESS\n", 8); rio_readlineb(riop, buf, MAXLINE); break; } token = strchr(buf, ':'); token[0] = '\0'; token++; token1 = strchr(token, ':'); token1[0] = '\0'; token1++; token1[strlen(token1)-1] = '\0'; if (check_in_database(buf, token,atoi(token1))) { rio_writen(connfd,"in database\n",12); continue; } database[ava_entry].title = (char *)malloc(strlen(buf)+1); strcpy(database[ava_entry].title, buf); database[ava_entry].host_name = (char *)malloc(strlen(token)+1); strcpy(database[ava_entry].host_name, token); database[ava_entry].port = atoi(token1); database[ava_entry].valid = TRUE; incre(ava_entry); rio_writen(connfd, "added\n", 6); } return TRUE;}/* * Deregister the exit client */int deregister_file(int connfd, rio_t* riop){ size_t n; char buf[MAXLINE]; char* token, *token1; int port,i; while((n = rio_readlineb(riop, buf, MAXLINE)) != 0) { if (strcmp(buf, ".\n") == 0) { rio_writen(connfd, "SUCCESS\n", 8); rio_readlineb(riop, buf, MAXLINE); fflush(stdout); break; } token = strchr(buf, ' '); token[0] = '\0'; token++; token[strlen(token)-1] = '\0'; port = atoi(token); for(i = 0; i < DATABASE; i++) { if (database[i].valid && !strcmp(database[i].host_name, buf) && (database[i].port == port)) { database[i].valid = FALSE; } } for(i = 0; i < DATABASE; i++) { if (!database[i].valid) break; } ava_entry = i; rio_writen(connfd,"doing\n",6); } return TRUE;}/* * Check the file entry whether in the database */int check_in_database(char *title, char* host, int port){ int i; for(i = 0; i < DATABASE; i++) { if (database[i].valid && !strcmp(database[i].title,title) && !strcmp(database[i].host_name, host) && (database[i].port == port)) { return TRUE; } } return FALSE; }/* * Print the database */void print_database(){ int i; for(i = 0; i < DATABASE; i++) { if (database[i].valid) { printf("%s %s:%d \n", database[i].title, database[i].host_name, database[i].port); } }}/* * Increase the database list entry. * ava_entry points to the smallest available entry. */void incre(int entry){ while(database[entry].valid && entry < DATABASE) entry++; if (entry == DATABASE) { printf("The file database is full!"); ava_entry = -1; } ava_entry = entry;}/* * Do the file query . */void query(int connfd, rio_t* riop){ size_t n; char buf[MAXLINE]; char *x; char *y; char *savept; char *portstr; int i; int find = FALSE; if ((n = rio_readlineb(riop, buf, MAXLINE)) != 0) { x = (char *)malloc(strlen(buf)+1); strcpy(x,buf); while((y=(char *)strtok_r(x," \t\r\n",&savept))!=NULL) { x = savept; i = 0; while(y[i]) { y[i] = tolower(y[i]); i++; } for(i = 0; i < DATABASE; i++) { if (database[i].valid) { if (strstr(database[i].title, y)) { rio_writen(connfd, database[i].title, strlen(database[i].title)); rio_writen(connfd, ":", 1); rio_writen(connfd, database[i].host_name, strlen(database[i].host_name)); portstr = (char *)malloc(7); sprintf(portstr, ":%d", database[i].port); rio_writen(connfd, portstr,strlen(portstr)); rio_writen(connfd, "\n", 1); find = TRUE; } } } } if (find) { rio_writen(connfd, "SUCCESS\n", 9); } else { rio_writen(connfd, "FAILED\n", 7); } }}/* * Listen for clients. */ int open_listenfd(int port){ int listenfd, optval = 1; struct sockaddr_in serveraddr; if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1; if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int)) < 0) return -1; bzero((char *)&serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons((unsigned short)port); if(bind(listenfd, (SA *)&serveraddr, sizeof(serveraddr)) < 0) return -1; if(listen(listenfd, LISTENQ) < 0) return -1; return listenfd;}/* The Rio package - robust I/O functions *//* * rio_readn - robustly read n bytes (unbuffered) */ssize_t rio_readn(int fd, void *usrbuf, size_t n) { size_t nleft = n; ssize_t nread; char *bufp = usrbuf; while (nleft > 0) { if ((nread = read(fd, bufp, nleft)) < 0) { if (errno == EINTR) /* interrupted by sig handler return */ nread = 0; /* and call read() again */ else return -1; /* errno set by read() */ } else if (nread == 0) break; /* EOF */ nleft -= nread; bufp += nread; } return (n - nleft); /* return >= 0 */}/* * rio_writen - robustly write n bytes (unbuffered) */ssize_t rio_writen(int fd, void *usrbuf, size_t n) { size_t nleft = n; ssize_t nwritten; char *bufp = usrbuf; while (nleft > 0) { if ((nwritten = write(fd, bufp, nleft)) <= 0) { if (errno == EINTR) /* interrupted by sig handler return */ nwritten = 0; /* and call write() again */ else return -1; /* errorno set by write() */ } nleft -= nwritten; bufp += nwritten; } return n;}/* * rio_read - This is a wrapper for the Unix read() function. */static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n){ int cnt; while (rp->rio_cnt <= 0) { /* refill if buf is empty */ rp->rio_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf)); if (rp->rio_cnt < 0) { if (errno != EINTR) /* interrupted by sig handler return */ return -1; } else if (rp->rio_cnt == 0) /* EOF */ return 0; else rp->rio_bufptr = rp->rio_buf; /* reset buffer ptr */ } /* Copy min(n, rp->rio_cnt) bytes from internal buf to user buf */ cnt = n; if (rp->rio_cnt < n) cnt = rp->rio_cnt; memcpy(usrbuf, rp->rio_bufptr, cnt); rp->rio_bufptr += cnt; rp->rio_cnt -= cnt; return cnt;}/* * rio_readinitb - Associate a descriptor with a read buffer and reset buffer */void rio_readinitb(rio_t *rp, int fd) { rp->rio_fd = fd; rp->rio_cnt = 0; rp->rio_bufptr = rp->rio_buf;}/* * rio_readnb - Robustly read n bytes (buffered) */ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n) { size_t nleft = n; ssize_t nread; char *bufp = usrbuf; while (nleft > 0) { if ((nread = rio_read(rp, bufp, nleft)) < 0) { if (errno == EINTR) /* interrupted by sig handler return */ nread = 0; /* call read() again */ else return -1; /* errno set by read() */ } else if (nread == 0) break; /* EOF */ nleft -= nread; bufp += nread; } return (n - nleft); /* return >= 0 */}/* * rio_readlineb - robustly read a text line (buffered) */ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen) { int n, rc; char c, *bufp = usrbuf; for (n = 1; n < maxlen; n++) { if ((rc = rio_read(rp, &c, 1)) == 1) { *bufp++ = c; if (c == '\n') break; } else if (rc == 0) { if (n == 1) return 0; /* EOF, no data read */ else break; /* EOF, some data was read */ } else return -1; /* error */ } *bufp = 0; return n;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -