简单的Client / Server 使用 linux 伯克利 socket实现
生活随笔
收集整理的這篇文章主要介紹了
简单的Client / Server 使用 linux 伯克利 socket实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
服務器:
/**run command:* g++ server.cpp -o server && ./server*/#ifndef SERVER #define SERVER#include<arpa/inet.h> #include<assert.h> #include<stdio.h> #include<stdlib.h> #include<pthread.h> #include<errno.h> #include<assert.h> #include<string.h> #include<sys/types.h> #include<unistd.h> #include<netinet/in.h> #include<sys/socket.h> #include<sys/wait.h> #include<signal.h>const int SERVPORT = 5555;//服務器監聽端口號 const int BACKLOG = 10; //最大同時連接請求數 const int MAX_DATA_SIZE = 1000;const int MAX_NAME_LENGTH = 21; const int MAX_PHONE_LENGTH = 15; const int MAX_HOMEADDRESS_LENGTH = 61;struct Address {char name[MAX_NAME_LENGTH];char phone[MAX_PHONE_LENGTH];char home_address[MAX_HOMEADDRESS_LENGTH];int age; }; //void insert_client_fd(int* client_list,int client_fd); //void accept_client(); //void* interact_with_client(void* clients_list); void* send_msg_to_client(int client_fd, char* msg); void sig_int(int signo); void generate_phone(char* phone); void generate_name(char* name); void generate_rand_n_address(int n); bool find_phone_with_name(char* name, char* phone); bool find_name_with_phone(char* phone, char* name); bool write_address(Address** addresses, int n); void print_addresses(); void handle_request(const int client_id, const char* buf); void init();void serv(); void client_add(int* client, int fd); void client_del(int* client, int fd);static char const* fileName = ".address"; //sock_fd:監聽socket static int sock_fd; /** 讀寫鎖*/ pthread_rwlock_t rwlock;int main(int argc, char* argv[]) {init();//accept_client();serv();return 0; } /** 初始化*/ void init() {if (signal(SIGINT, sig_int) == SIG_ERR){perror("signal(SIGINT,sig_int)");}if (signal(SIGQUIT, sig_int) == SIG_ERR){perror("signal(SIGQUIT,sig_int)");}srand(time(0));print_addresses();//每次隨機產生10個//generate_rand_n_address(10); }void serv() {if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket創建出錯");_exit(1);}//本地地址信息struct sockaddr_in my_addr;my_addr.sin_family = AF_INET;my_addr.sin_port = htons(SERVPORT);my_addr.sin_addr.s_addr = INADDR_ANY;INADDR_ANY;inet_addr(serverIP);//printf("%s\n", inet_ntoa(my_addr.sin_addr));bzero(&(my_addr.sin_zero), 8);printf("before bind\n");if (bind(sock_fd, (struct sockaddr*) &my_addr, sizeof(my_addr)) == -1){perror("bind出錯!");exit(1);}printf("before listen\n");if (listen(sock_fd, BACKLOG) == -1){perror("listen出錯");exit(1);}int client[BACKLOG + 1];memset(client, -1, sizeof(int) * (BACKLOG + 1));/** 最大的fd*/int maxfd;fd_set rset, allset;FD_ZERO(&allset);FD_SET(sock_fd,&allset);maxfd = sock_fd;for (;;){rset = allset;if (select(maxfd + 1, &rset, NULL, NULL, NULL) < 0){perror("select error");}//client_fd:數據傳輸socketint client_fd;char buf[MAX_DATA_SIZE];//監聽fd 準備好了if (FD_ISSET(sock_fd,&rset)){//客戶端地址信息struct sockaddr_in remote_addr;socklen_t sin_size;sin_size = sizeof(struct sockaddr_in);printf("before accept\n");if ((client_fd = accept(sock_fd, (struct sockaddr*) &remote_addr,&sin_size)) == -1){perror("accept出錯\n");continue;}client_add(client, client_fd);FD_SET(client_fd,&allset);//調整maxfdif(client_fd>maxfd)maxfd=client_fd;printf("received a connection from %s assigned fd=%d\n", inet_ntoa(remote_addr.sin_addr), client_fd);if (vfork() == 0){//服務程序:子進程//完成發送消息后,退出char buf[MAX_DATA_SIZE];sprintf(buf, "Hello,Your Number is %d", client_fd);send_msg_to_client(client_fd, buf);exit(0);}}//有客戶端發來請求for (int i = 0; i <= BACKLOG; i++){client_fd = client[i];//printf("client[%d]=%d\n",i,client_fd);//client_fd有請求if (client_fd > 0 && FD_ISSET(client_fd,&rset)){int receivebytes = recv(client_fd, buf, MAX_DATA_SIZE, 0);if(receivebytes<0){perror("recv error!");}else if(receivebytes==0){FD_CLR(client_fd,&allset);client_del(client,client_fd);close(client_fd);}else{buf[receivebytes] = '\0';printf("received cmd from %d:%s\n", client_fd, buf);if (strncmp(buf, "quit", 4) == 0){FD_CLR(client_fd,&allset);client_del(client,client_fd);close(client_fd);printf("client_fd id=%lu quit\n", client_fd);}elsehandle_request(client_fd, buf);}}//if (client_fd > 0 && FD_ISSET(client_fd,&rset))}//for (int i = 0; i <= maxfd; i++)} } void client_add(int* client, int fd) {for (int i = 0; i <= BACKLOG; i++){if (client[i] == -1){client[i] = fd;break;//居然兩次,都忘記了break,編程水平太低了...}} } void client_del(int* client, int fd) {for (int i = 0; i <= BACKLOG; i++){if (client[i] == fd)client[i] = -1;} }void handle_request(const int client_id, const char* buf) {char* helpString = "help #顯示可用的命令\n""list #顯示通訊錄所有內容(假設沒有重名)\n""name TheNameString#查詢手機號\n""phon ThePhoneNumberString#phone 查詢名字\n""shel #本地shell \n""quit #quit\n""inse #insert 暫時不實現\n";if (strncmp(buf, "help", 4) == 0){send_msg_to_client(client_id, helpString);}else if (strncmp(buf, "list", 4) == 0){FILE* fp = fopen(fileName, "r");if (fp == NULL){perror("fopen error!");return;}else{Address addr;char buf[MAX_DATA_SIZE];int count = 1;while (fread(&addr, sizeof(Address), 1, fp) == 1){sprintf(buf, "%-5dname:'%s',phone=%s,home_address=%s,age:%d\n",count, addr.name, addr.phone, addr.home_address,addr.age);//一次發送一條記錄send_msg_to_client(client_id, buf);count++;}}fclose(fp);}else if (strncmp(buf, "name", 4) == 0){char name[MAX_NAME_LENGTH];strcpy(name, buf + 5);printf("name=%s\n", name);char phone[MAX_PHONE_LENGTH];phone[0] = '\0';find_phone_with_name(name, phone);char buf[MAX_DATA_SIZE];if (strlen(phone) > 0){sprintf(buf, "phone=%s\n", phone);}else{sprintf(buf, "No such Name=%s\n", name);}send_msg_to_client(client_id, buf);}else if (strncmp(buf, "phon", 4) == 0){char phone[MAX_PHONE_LENGTH];strcpy(phone, buf + 5);printf("phone=%s\n", phone);char name[MAX_NAME_LENGTH];name[0] = '\0';find_name_with_phone(name, phone);char buf[MAX_DATA_SIZE];if (strlen(name) > 0){sprintf(buf, "name=%s\n", name);}else{sprintf(buf, "No such Phone Number=%s\n", phone);}send_msg_to_client(client_id, buf);}/** 在線程中,不可以放在handle_request中處理* (還沒有找到原因)*/else{char temp[MAX_DATA_SIZE];sprintf(temp, "Unknow Command:%s\n\ttry help\n", buf);send_msg_to_client(client_id, temp);} } /** 保證SIGINT,SIGQUIT,可以正常關閉連接*/ void sig_int(int signo) {printf("\nclose(%d)\nexit\n", sock_fd);close(sock_fd);_exit(0); }/** 發送消息到client_fd*/ void* send_msg_to_client(int client_fd, char* msg) {assert(msg!=NULL);if (send(client_fd, msg, strlen(msg), 0) == -1){perror("send出錯\n");}return NULL; }/** 隨機產生 n 項*/ void generate_rand_n_address(int n) {Address** addresses = (Address**) malloc(sizeof(Address*) * n);for (int i = 0; i < n; i++){addresses[i] = (Address*) malloc(sizeof(Address));generate_name(addresses[i]->name);generate_phone(addresses[i]->phone);addresses[i]->age = rand() % 100 + 10;printf("generate:name->%s\tphone->%s\tage=%d\n", addresses[i]->name,addresses[i]->phone, addresses[i]->age);}write_address(addresses, n);//釋放空間for (int i = 0; i < n; i++)free(addresses[i]);free(addresses); } /** 將數組addresses,n個address寫入文件*/ bool write_address(Address* addresses[], int n) {FILE* fp = fopen(fileName, "a");if (fp == NULL){perror("fopen error!\n");exit(1);}else{for (int i = 0; i < n; i++)if (fwrite(addresses[i], sizeof(Address), 1, fp) < 0){perror("fwrite error!\n");exit(1);}}fclose(fp);return 1; }/** 查找name 用電話號碼 phone*/ bool find_name_with_phone(char* name, char* phone) {assert(name!=NULL);assert(phone!=NULL);FILE* fp = fopen(fileName, "r");if (fp == NULL){perror("fopen error!\n");return 0;}else{Address addr;while (fread((char*) &addr, sizeof(Address), 1, fp) == 1){if (strcmp(addr.phone, phone) == 0){strcpy(name, addr.name);return 1;}}}return 0; } /** 重名的 返回文件中第一個名字的phone* 成功則,phone是結果并返回1,否則返回0,phone不變*/ bool find_phone_with_name(char* name, char* phone) {assert(name!=NULL);assert(phone!=NULL);FILE* fp = fopen(fileName, "r");if (fp == NULL){perror("fopen error!\n");return 0;}else{Address addr;while (fread((char*) &addr, sizeof(Address), 1, fp) == 1){if (strcmp(addr.name, name) == 0){strcpy(phone, addr.phone);return 1;}}}return 0; } /** 將文件(若有)的所有通訊錄輸出到標準輸出*/ void print_addresses() {FILE* fp = fopen(fileName, "r");if (fp == NULL){perror("fopen error!");return;}else{Address addr;int count = 1;while (fread(&addr, sizeof(Address), 1, fp) == 1){printf("%-5dname:'%s',phone=%s,home_address=%s,age:%d\n", count,addr.name, addr.phone, addr.home_address, addr.age);count++;}}fclose(fp);}/** 隨機生成一個字符串 長度小于 MAX_NAME_LENGTH*/ char* alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; void generate_name(char* name) {int len = rand() % MAX_NAME_LENGTH;if (len < 5){len += 5;}for (int i = 0; i < len; i++){name[i] = alphabet[rand() % (sizeof(alphabet))];}name[len] = '\0'; }/** 產生11位的電話號碼*/ char* number = "0123456789"; void generate_phone(char* phone) {phone[0] = '1';for (int i = 1; i < 11; i++){phone[i] = number[rand() % 10];}phone[11] = '\0';//末尾 }#endif //客戶端:
/** run command* g++ client.cpp -o client && ./client 192.168.111.139#serverIP*/#ifndef CLIENT #define CLIENT #include<sys/select.h> #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<netdb.h> #include<sys/types.h> #include<unistd.h> #include<pthread.h> #include<arpa/inet.h> #include<netinet/in.h> #include<signal.h> #include<sys/socket.h>const int SERVPORT = 5555; const int MAX_DATA_SIZE = 1000;//每次最大數據傳輸量//void* send_msg_to_server(void* args); void* interact_with_server(void* agrs); void sig_int(int signo);static int sockfd = -1;int main(int argc, char* argv[]) {if (signal(SIGINT, sig_int) == SIG_ERR){perror("signal(SIGINT,sig_int)");}if (signal(SIGQUIT, sig_int) == SIG_ERR){perror("signal(SIGQUIT,sig_int)");}if (argc < 2){printf("請輸入server IP\n");exit(1);}char* serverIP = argv[1];struct sockaddr_in serv_addr;serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(SERVPORT);serv_addr.sin_addr.s_addr = inet_addr(serverIP);//*((struct in_addr*)host->h_addr);printf("serverIP:%s\n", inet_ntoa(serv_addr.sin_addr));bzero(&(serv_addr.sin_zero), 8);int recvbytes;char buf[MAX_DATA_SIZE];if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket創建出錯!");exit(1);}if (connect(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1){perror("connect出錯!");sleep(1);}if (sockfd < 0){return NULL;}//用于selectfd_set readSet;FD_ZERO(&readSet);FD_SET(sockfd,&readSet);//FD_SET(STDIN_FILENO,&readSet);int reseivebytes;//char buf[MAX_DATA_SIZE];while (1){fd_set readSet_temp;readSet_temp = readSet;//一次使用 1s接收數據timeval tvptr;tvptr.tv_sec = 1;tvptr.tv_usec = 0;bool flag_recived = 0;int rs;while ((rs = select(sockfd + 1, &readSet_temp, NULL, NULL, &tvptr)) > 0){flag_recived = 1;//recv準備好了if ((reseivebytes = recv(sockfd, buf, MAX_DATA_SIZE, 0)) == -1){perror("recv 錯誤!\n");exit(1);}else if (reseivebytes > 0){buf[reseivebytes] = '\0';printf("received msg from server:\n%s\n", buf);}else if (reseivebytes < 0){//連接已斷開printf("close(%d)\n", sockfd);close(sockfd);return NULL;}memset(buf, 0, MAX_DATA_SIZE);//readSet_temp還原readSet_temp = readSet;}if (rs < 0){perror("select!");}/**沒有recv不必輸出提示信息*///if(flag_recived==1)printf("input cmd sended to server-->");/** 讀入一行(包含末尾的'\n'),去除'\n'='\0'*/fgets(buf, MAX_DATA_SIZE, stdin);/** 空行不發送*/if (strlen(buf) > 1){buf[strlen(buf) - 1] = '\0';if (strncmp(buf, "shel", 4) == 0){system(buf + 5);}else if (send(sockfd, buf, strlen(buf), 0) == -1){perror("send 出錯!\n");}if (strncmp(buf, "quit", 4) == 0){close(sockfd);exit(0);}}}close(sockfd);return 0; } void sig_int(int signo) {printf("\nclose(%d)\n", sockfd);close(sockfd);_exit(0); }#endif轉載于:https://www.cnblogs.com/fengjunfeng/archive/2012/05/29/2797778.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的简单的Client / Server 使用 linux 伯克利 socket实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pip 安装
- 下一篇: 日语开发java自我介绍,优秀日语自我介