服务器使用select模型搭建,客户端1使用线程搭建,客户端2使用poll模型搭建,
使用时需要先运行服务器,具体编译可看我最后的图片
head.h头文件
#ifndef __HEAD_H_ #define __HEAD_H_
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/stat.h> #include <pwd.h> #include <dirent.h> #include <wait.h> #include <errno.h> #include <pthread.h> #include <semaphore.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/shm.h> #include <sys/sem.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <poll.h> #include <signal.h> #define PRINTF_ERROR(a) {perror(a);return -1;} #endif
服务器搭建代码
server_select.c
#include <head.h> enum Type{ TYPE_LOGIN, TYPE_REDIST }; typedef struct Pack{ //协议包 int packsize; enum Type type; char buf[4096]; int used;
}pack_t; void freeList(char** list){ for(int i=0;list[i]!=NULL;i++){ free(list[i]); } free(list); }
char** analysis(pack_t pack){ //解析客户端发来的协议包 char* buf=pack.buf; int readed_size=0; char** list = calloc(1,80); int i=0;// while(1){ short size = *(short*)(buf+readed_size); if(size==0) break; readed_size+=2; char temp[size+1]; memset(temp,0,size+1); memcpy(temp,buf+readed_size,size); readed_size+=size;
list[i]=calloc(1,size+1); strcpy(list[i],temp); i++; } return list;
} void insert_client(int* arr,int client,int* len){ //将客户端的描述符放入数组 arr[*len]=client; (*len)++; } void remove_client(int* arr,int client,int* len){ int i=0,j=0; for(i=0;i<*len;i++){ if(arr[i]==client) break; } if(i==*len) return; for(j=i;j<*len;j++){ arr[j]=arr[j+1]; } arr[j]=0; (*len–); } int main(int argc, const char *argv[]) { if(argc<2){ printf("请输入端口号:\\n"); return 1; } int port = atoi(argv[1]); int server = socket(AF_INET,SOCK_STREAM,0); struct sockaddr_in addr = {0};
addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr("0.0.0.0"); if(bind(server,(struct sockaddr*)&addr,sizeof(addr))==-1){ perror("bind"); return -1; } listen(server,50);
int client_arr[64]={0};//存放所有客户端套接字的数组 int arr_len=0;//记录数组的长度 fd_set readfds;//创建一个select的监听列表 FD_ZERO(&readfds);//初始化监听列表 FD_SET(server,&readfds);//将服务器套接字放入监听列表中 FD_SET(STDIN_FILENO,&readfds);//将标准输入流放入监听列表中
while(1){ fd_set temp=readfds; select(1024,&temp,0,0,0); if(FD_ISSET(0,&temp)){ 输入流激活 char buf[1024]=""; scanf("%s",buf); getchar(); printf("键盘输入数据:%s\\n",buf); } if(FD_ISSET(server,&temp)){ 服务器激活 int client=accept(server,0,0); printf("有客户端链接\\n"); FD_SET(client,&readfds); insert_client(client_arr,client,&arr_len); } for(int i=0;i<arr_len;i++){ int client = client_arr[i]; if(FD_ISSET(client,&temp)){ //客户端激活
pack_t pack={0}; int size=0; int res=read(client,&size,4); if(res ==0){ printf("客户端断开链接\\n"); FD_CLR(client,&readfds); remove_client(client_arr,client,&arr_len); close(client); break; } pack.packsize=size; read(client,(char*)&pack+4,size-4); char** list=analysis(pack); for(int j=0;j<arr_len;j++){ if(client_arr[i]!=client_arr[j]){ if(write(client_arr[j],&pack,size)<=0) PRINTF_ERROR("write error"); } } printf("%s\\n",list[0]); freeList(list);
} } } return 0; }
客户端1
client1.c
#include <head.h> #include <pthread.h> enum Type{ TYPE_REGIST, TYPE_LOGIN };
typedef struct Pack{ int packsize; enum Type type; char buf[4096]; int used; }pack_t;
void append(pack_t* pack,const char* str){ char* buf=pack->buf; short size=strlen(str); *(short*)(buf+pack->used)=size; pack->used+=2; memcpy(buf+pack->used,str,size); pack->used+=size; pack->packsize=pack->used+8; } void freeList(char** list){ for(int i=0;list[i]!=NULL;i++){ free(list[i]); } free(list); }
char** analysis(pack_t pack){ char* buf=pack.buf; int readed_size=0; char** list = calloc(1,80); int i=0;// while(1){ short size = *(short*)(buf+readed_size); if(size==0) break; readed_size+=2; char temp[size+1]; memset(temp,0,size+1); memcpy(temp,buf+readed_size,size); readed_size+=size;
list[i]=calloc(1,size+1); strcpy(list[i],temp); i++; } return list;
}
void* Write(void* arg){ int client =*(int *)arg; while(1){ char str[20]=""; pack_t pack={0}; pack.type=TYPE_REGIST; scanf("%19s",str); getchar(); append(&pack,str); write(client,&pack,pack.packsize); } pthread_exit(NULL);
} void* Read(void* arg){ int client =*(int *)arg; while(1){ pack_t pack1={0}; int size=0; read(client,&size,4); read(client,(char*)&pack1+4,size-4); char** list=analysis(pack1); printf("客户端1:%s\\n",list[0]); freeList(list);
} pthread_exit(NULL); } int main(int argc, const char *argv[]) { if(argc<2){ printf("请输入端口号\\n"); return -1; } int port=atoi(argv[1]); int client=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in addr={0}; addr.sin_family=AF_INET; addr.sin_port=htons(port); addr.sin_addr.s_addr=inet_addr("0.0.0.0"); if(connect(client,(struct sockaddr*)&addr,sizeof(addr))==-1){ PRINTF_ERROR("bind error"); }
pthread_t tid1,tid2; pthread_create(&tid1,NULL,Write,&client); pthread_create(&tid2,NULL,Read,&client); pthread_join(tid1,NULL); pthread_join(tid2,NULL);
return 0; }
客户端2
client2.c
#include <head.h> enum Type{ TYPE_LOGIN, TYPE_REDIST }; typedef struct Pack{ int packsize; enum Type type; char buf[4096]; int used;
}pack_t; void append(pack_t* pack,const char* str){ char* buf = pack->buf; short size = strlen(str); *(short*)(buf+pack->used) = size; pack->used +=2; memcpy(buf+pack->used,str,size); pack->used+=size; pack->packsize=pack->used+8; } // 该函数功能为:将client存入数组arr中的最后一个下标位置上,存完之后,arr数组的长度记得自增 void insert_client(struct pollfd* arr,struct pollfd client,int* len){ arr[*len] = client; (*len)++; }
// 将client从数组arr中移除,移除后记得数组长度-1 void remove_client(struct pollfd* arr,int client,int* len){ int i = 0,j = 0; for(i=0;i<*len;i++){ if(arr[i].fd == client){break;} } if(i == *len){return;} for(j=i;j<*len-1;j++){ arr[j] = arr[j+1]; } //arr[j] = 0; (*len)–; } void freeList(char** list){ for(int i=0;list[i]!=NULL;i++){ free(list[i]); } free(list); }
char** analysis(pack_t pack){ char* buf=pack.buf; int readed_size=0; char** list = calloc(1,80); int i=0;// while(1){ short size = *(short*)(buf+readed_size); if(size==0) break; readed_size+=2; char temp[size+1]; memset(temp,0,size+1); memcpy(temp,buf+readed_size,size); readed_size+=size;
list[i]=calloc(1,size+1); strcpy(list[i],temp); i++; } return list;
}
int main(int argc, const char *argv[]) { if(argc<2){ printf("请输入端口号:\\n"); return 1; } int port = atoi(argv[1]);
int client = socket(AF_INET,SOCK_STREAM,0); struct sockaddr_in addr = {0}; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr("0.0.0.0"); if(connect(client,(struct sockaddr*)&addr,sizeof(addr))==-1){ perror("connect"); return -1; }
struct pollfd list[50]={0}; int list_len=0; struct pollfd client_fd={fd:client,events:POLLIN,revents:0}; struct pollfd stdin_fd={fd:0,events:POLLIN,revents:0};
insert_client(list,client_fd,&list_len);
insert_client(list,stdin_fd,&list_len);
while(1){
poll(list,list_len,-1); int i=0; for(i=0;i<list_len;i++){ if(list[i].revents==0){ continue; } int fd=list[i].fd; if(fd==0){ char str[20]=""; pack_t pack = {0}; pack.type=TYPE_REDIST; scanf("%19s",str); getchar(); append(&pack,str); write(client,&pack,pack.packsize); }else{ pack_t pack1={0}; int size=0; read(client,&size,4); read(client,(char*)&pack1+4,size-4); char** list=analysis(pack1); printf("客户端2:%s\\n",list[0]); freeList(list);
} } }
return 0; }
评论前必须登录!
注册