仿QQ聊天软件服务器

#include “myhead.h”
#include “kernel_list.h”
/*
tcp实现多人聊天
多客户端连接服务器,服务器作为中转站
服务器的代码
自己制定的通信协议是:
ip:真实信息 --》表示发给ip是这个的主机
server:真实信息 --》表示直接发给服务器
all:真实信息 --》发送给所有连接成功的客户端(排除自己)
*/
//定义内核链表对应的结构体
struct clientlist
{
char ip[16];//存放ip
unsigned short someport;//存端口号
int somesock; //存新套接字的
//扩展
char name[10];
int number;
struct clientlist *next;
};
int number;
struct clientlist *init_list()//初始化链表
{
struct clientlist *head=malloc(sizeof(struct clientlist));

if(head==NULL)
{
	printf("内存分配失败!\n");
	exit(-1);
}
head->next=NULL;
return head;

}

//链接节点
void add(struct clientlist *head,char * ip,unsigned short someport,int somesock,int number)
{
struct clientlist *p=head;
struct clientlist *newnode=malloc(sizeof(struct clientlist));
strcpy(newnode->ip,ip);
newnode->someport=someport;
newnode->somesock=somesock;
newnode->number=number;
newnode->next=NULL;

//遍历链表,找到尾部
while(p->next!=NULL)
{
	p=p->next;
}
//插入新的数据
p->next=newnode;

}

void delete(struct clientlist *head,char * ip)//删除节点
{
while(head->next!=NULL)
{
struct clientlist *q=head;
head=head->next;
if(strcmp(head->ip,ip)==0)
{
q->next=head->next;
free(head);
break;
}
}
}

int send_client(char * path,int newfd)
{
printf(“path:%s\n”,path);
int bmpfd,ret;
//打开文件
bmpfd=open(path,O_RDWR);
if(bmpfd==-1)
{
perror(“File opening failed!\n”);
return -1;
}

 int size=lseek(bmpfd,0,SEEK_END);//求文件的大小
 printf(" file size:%d\n",size);
 //依照文件实际大小定义数组
 char buf[size];
 lseek(bmpfd,0,SEEK_SET);//将文件指针移到文件开头
 //将文件大小发送给客户端
 ret=send(newfd,&size,sizeof(int),0);
 bzero(buf,sizeof(buf));
 read(bmpfd,buf,size);
 //将文件发送给客户端
 ret=send(newfd,buf,size,0);
 printf("Size of the sending fil:%d\n",ret);

return 0;

}

int receive_client(char * bmppath,int fd)
{
printf(“receive:%s\n”,bmppath);
int size,ret,bmpfd,ret1;
//接收文件大小信息
ret=recv(fd,&size,sizeof(int),0);
if(ret==-1)
{
perror(“Failed to receive file siz!\n”);
return -1;
}
//依照文件实际大小定义数组
char buf[size];
//接收文件
bzero(buf,sizeof(buf));
ret=recv(fd,buf,size,MSG_WAITALL);
if(ret==-1)
{
perror(“Failed to receive file!\n”);
return -1;
}
printf(“Receive File size:%d\n”,ret);
//创建一个文件
bmpfd=open(bmppath,O_CREAT|O_RDWR|O_TRUNC,0777);
if(bmpfd==-1)
{
perror(“File creation failed!\n”);
return -1;
}
ret1=write(bmpfd,buf,ret);
if(ret1==-1)
{
perror(“Write file failed!\n”);
}

close(bmpfd);

return 0;

}

//封装线程的功能函数
void *recvclient(void *arg)
{
int a=0;
int ret;

struct clientlist *p=(struct clientlist *)arg;

struct clientlist *pos;
struct clientlist *qos;
char rbuf[2000];
char allbuf[200];
char buf1[20];
char buf2[50];
char sbuf[4096];
int flag=1;
char fbuf[50];
char * str,* str1,* str2;
while(p->next!=NULL)
{
	p=p->next;
	a++;
}
a--;



bzero(rbuf,sizeof(rbuf));
sprintf(rbuf,"/mnt/hgfs/1.10/project.client/server/%d.bmp",number);

receive_client(rbuf,p->somesock);
printf("%s\n",rbuf);
while(1)
{
		
	flag=0; //重新置零
	bzero(rbuf,2000);
	bzero(buf1,20);
	bzero(buf2,50);
	bzero(sbuf,4096);
	bzero(fbuf,50);
	
	ret=recv(p->somesock,rbuf,2000,0);//接收某个客户端发送过来的信息
	
	if(ret==0) //说明客户端断开连接了
	{
		//遍历内核链表删除断开的客户端
		pos=((struct clientlist *)arg)->next;
		while(pos!=NULL)
		{
			if(strcmp(pos->ip,p->ip)!=0)
			{
				bzero(sbuf,sizeof(sbuf));
				sprintf(sbuf,"down:%s",p->ip);
				send(pos->somesock,sbuf,sizeof(sbuf),0);
			}
			pos=pos->next;
		}
		delete((struct clientlist *)arg,p->ip);
		
		pthread_exit(NULL);
	}
	
	//判断客户端发送过来是不是getlist
 
	if(strncmp(rbuf,"user",4)==0)
	{
		//将用户链表的信息发送给客户端,遍历链表将所有的信息发送给客户端
		send(p->somesock,&a,sizeof(a),0);
		pos=((struct clientlist *)arg)->next;
		
		printf("1fasong\n");
		while(pos!=NULL)
		{
			
			if(strcmp(pos->ip,p->ip)!=0)
			{
				bzero(sbuf,sizeof(sbuf));
				sprintf(sbuf,"%s:%hu:%d:%d",pos->ip,pos->someport,pos->somesock,pos->number);
				send(pos->somesock,sbuf,sizeof(sbuf),0);
				
				bzero(sbuf,sizeof(sbuf));
				sprintf(sbuf,"/mnt/hgfs/1.10/project.client/server/d.bmp",pos->number);
				send_client(sbuf,p->somesock);
				printf("fasong\n");
			}
			pos=pos->next;
		}
			
				
		
		printf("getlist1\n");
		qos=((struct clientlist *)arg)->next;
		while(pos!=NULL)
		{
			if(strcmp(qos->ip,p->ip)!=0)
			{
				printf("fasong3\n");
				bzero(sbuf,sizeof(sbuf));
				sprintf(sbuf,"go online:%s:%hu:%d:%d",qos->ip,qos->someport,qos->somesock,qos->number);
				send(qos->somesock,sbuf,sizeof(sbuf),0);
				
				bzero(sbuf,sizeof(sbuf));
				sprintf(sbuf,"/mnt/hgfs/1.10/project.client/server/d.bmp",pos->number);
				send_client(sbuf,p->somesock);
			}
			pos=pos->next;
		}
			
				
		
		printf("getlist2\n");
	
	}
	else//说明想发送给某个客户端
	{
		//遍历链表找到对应ip地址的客户端
		str=strtok(rbuf,":");
		pos=((struct clientlist *)arg)->next;
		while(pos!=NULL)
		{
			if(pos->somesock==p->somesock)
			{
				str1=strtok(NULL,":");
				bzero(sbuf,sizeof(sbuf));
				sprintf(sbuf,"%s:%s",p->ip,str1);
				send(pos->somesock,sbuf,sizeof(sbuf),0);
			}
			pos=pos->next;
		}
		
		
			
	}
	
	
}

}

int main(int argc,char **argv)
{
int iphonex;
pthread_t id;
//定义新的变量存放新的套接字
int newsock;
int ret;
struct clientlist *pos;
//定义一个ipv4地址结构体变量并初始化
struct sockaddr_in bindaddr;
bzero(&bindaddr,sizeof(bindaddr));
bindaddr.sin_family=AF_INET;
//由于存在字节序的问题,需要转换
bindaddr.sin_port=htons(atoi(argv[1]));//程序员自己指定,服务器的端口号
bindaddr.sin_addr.s_addr=htonl(INADDR_ANY);//绑定服务器自己的ip

struct sockaddr_in boyaddr;
int addrsize=sizeof(boyaddr);

//初始化内核链表的头结点

//买手机--》创建tcp套接字
iphonex=socket(AF_INET,SOCK_STREAM,0);
if(iphonex==-1)
{
	perror("创建tcp失败!\n");
	return -1;
}
int value=1;
//取消绑定限制
setsockopt(iphonex,SOL_SOCKET,SO_REUSEADDR,&value,sizeof(value));

//绑定ip地址和端口号
ret=bind(iphonex,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
if(ret==-1)
{
	perror("绑定失败!\n");
	return -1;
}
//监听
ret=listen(iphonex,6);
if(ret==-1)
{
	perror("监听失败!\n");
	return -1;
}
printf("阻塞在accept!\n");

while(1)
{
	//接受多个客户端的连接请求
	newsock=accept(iphonex,(struct sockaddr *)&boyaddr,&addrsize);  
	if(newsock==-1)
	{
		perror("接受连接请求失败!\n");
		return -1;
	}
	printf("连接成功的客户端ip是:%s  端口号是:%hu  对应的套接字是:%d\n",inet_ntoa(boyaddr.sin_addr),ntohs(boyaddr.sin_port),newsock);
	//将boyaddr里面存放的ip和端口号,newsock一起打包放入链表中
	//准备新的节点
	number++;
	
	struct clientlist *mylist=init_list();
	add(mylist,inet_ntoa(boyaddr.sin_addr),ntohs(boyaddr.sin_port),newsock,number);
	
	
	//创建一个线程专门用来接收这个客户端的发送的信息
	pthread_create(&id,NULL,recvclient,mylist);
	pthread_detach(id);
}
//挂机
close(iphonex);
return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值