#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;
}