网络编程之客户端通过服务器与另外一个客户端交流
服务器使用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;
}