服务器:
/**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