#ifndef HHHH
#define HHHH
#include<myhead.h>
typedef struct Node
{
int len;
char name[128];
struct sockaddr_in cin;
struct Node*next;
}No,*NodePtr;
//创建头结点
NodePtr create();
int list_empty(NodePtr L);//判空
NodePtr pos(char*name,struct sockaddr_in cin);//封装
int bianli(NodePtr L,struct sockaddr_in cin);//按信息返回位置
int add(NodePtr L,char*name,struct sockaddr_in cin);//添加节点
int kan(NodePtr L);//打印在线人数信息
int list_sendto(NodePtr L,int sfd,char*rbuf);//向在线人员发送信息
int list_send(NodePtr L,int sfd,char*rbuf);//下线信息发送
NodePtr find(NodePtr L,struct sockaddr_in cin);//按数据查找地址
NodePtr wei(NodePtr L,int len);//按位置查找地址
int list_delete(NodePtr L,struct sockaddr_in cin);//删除节点
int tou(NodePtr L);//全部删除
#endif
#include"work1.h"
NodePtr create()//创建头结点
{
NodePtr L=(NodePtr)malloc(sizeof(No));//申请空间
if(NULL==L)
{
printf("申请失败\n");
return NULL;
}
bzero(L,sizeof(No));//初始化结点
L->len=0;
L->next==NULL;
return L;
}
int list_empty(NodePtr L)
{
return L==NULL;//返回值为判断条件
}
NodePtr pos(char*name,struct sockaddr_in cin)//封装
{
NodePtr L=(NodePtr)malloc(sizeof(No));
if(NULL==L)
{
printf("申请失败\n");
return NULL;
}
bzero(L,sizeof(No));
strcpy(L->name,name);//填充信息
L->cin=cin;
L->next=NULL;
return L;
}
int bianli(NodePtr L,struct sockaddr_in cin)//按信息返回位置
{
if(L==NULL)
{
printf("遍历失败\n");
return -1;
}
int arr=1;
struct sockaddr_in sin =cin;//填充信息
char *p1=inet_ntoa(sin.sin_addr);//填充信息
char *p2=NULL;
int p3=ntohs(sin.sin_port);//填充信息
int p4;
NodePtr P=L->next;
while(P!=NULL)
{
p2=inet_ntoa(P->cin.sin_addr);//获取信息
p4=ntohs(P->cin.sin_port);
if((strcmp(p1,p2)==0)&&(p3==p4))//比较内容
{
return arr;
}
arr++;
P=P->next;
}
p1=NULL;//清空指针
p2=NULL;
return 0;
}
int kan(NodePtr L)
{
if(L==NULL||list_empty(L))
{
printf("遍历失败\n");
return -1;
}
NodePtr P=L->next;
printf("[在线列表]当前在线人数:%d\n",L->len);//打印在线人数
while(P!=NULL)
{
printf("[%s,%d]:%s\n",inet_ntoa(P->cin.sin_addr),ntohs(P->cin.sin_port),P->name);//打印在线人数信息
P=P->next;
}
return 0;
}
int add(NodePtr L,char*name,struct sockaddr_in cin)//添加
{
if(L==NULL)
{
printf("添加失败\n");
return -1;
}
NodePtr l=pos(name,cin);//封装节点返回地址
NodePtr q=L;
while(1)
{
if(q->next==NULL)//循环查找最后一个节点
{
q->next=l;//添加地址
break;
}
q=q->next;
}
L->len++;//链表长度增加
return 0;
}
int list_sendto(NodePtr L,int cfd,char*rbuf)//向所有人发送信息
{
if(NULL==L,list_empty(L))
{
printf("发送失败\n");
return -1;
}
int sfd=cfd;
char buf[128]="";
strcpy(buf,rbuf);
NodePtr P=L->next;
while(P!=NULL)//循环进入所有节点
{
strcpy(buf,rbuf);
if(sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&(P->cin),sizeof(P->cin))==-1)//发送信息
{
perror("send");
return -1;
}
P=P->next;
}
return 0;
}
NodePtr find(NodePtr L,struct sockaddr_in cin)//按数据找地址
{
if(NULL==L||list_empty(L))
{
printf("查找失败\n");
return NULL;
}
int a=bianli(L,cin);//获取节点所在位置
NodePtr P=wei(L,a);//获取位置所在地址
return P;
}
NodePtr wei(NodePtr L,int len)//按位置查找
{
if(NULL==L||list_empty(L)||len<1||len>L->len)
{
printf("查找失败\n\n");
return NULL;
}
NodePtr P=L;
for(int i=1;i<=len;i++)//按位置查找节点返回地址
{
P=P->next;
}
return P;
}
int list_delete(NodePtr L,struct sockaddr_in cin)//删除
{
if(NULL==L||list_empty(L))
{
printf("删除失败\n");
return -1;
}
struct sockaddr_in sin=cin;//获取信息
int arr=bianli(L,sin);
if(arr==1)//如果是头节点直接删除
{
NodePtr n=L->next;
L->next=L->next->next;
free(n);
n=NULL;
}else if(arr>1)//如果不是头节点获取地址再删除
{
NodePtr q=wei(L,arr-1);
NodePtr e=q->next;
q->next=q->next->next;
free(e);
}
L->len--;//链表长度减少
return 0;
}
int list_send(NodePtr L,int cfd,char*name)//死亡发送
{
if(NULL==L||list_empty(L))
{
printf("发送失败\n");
return -1;
}
int sfd=cfd;
char buf[128]="";
NodePtr P=L->next;
while(P!=NULL)
{
strcpy(buf,name);//获取下线信息
if(sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&(P->cin),sizeof(P->cin))==-1)//向在线用户发送下线信息
{
perror("send");
return -1;
}
P=P->next;
}
return 0;
}
int tou(NodePtr L)//全部删除
{
if(L==NULL)
{
printf("头删除失败\n");
}
NodePtr q=NULL;//定义地址指针
while(L->next!=NULL)//循环头删
{
q=L->next;
L->next=L->next->next;
free(q);//释放空间
q=NULL;//指针指向空
L->len--;//减少链表长度
}
free(L);//释放头结点
L=NULL;//释放指针
return 0;
}
#include "work1.h"
struct NB//创建结构体
{
int sfd;
char name[128];
char text[128];
struct sockaddr_in sin;
NodePtr L;
};
void* stak1(void*arg)
{
NodePtr P=NULL;
NodePtr Q=NULL;
char rbuf[128]="";
char name[128]="";
char crr[128]="";
char drr[128]="";
NodePtr L=(*(struct NB*)arg).L;//获取链表头结点地址
int sfd=(*(struct NB*)arg).sfd;//获取套接字符
struct sockaddr_in sin=(*(struct NB*)arg).sin;//获取结构体信息
socklen_t addrlen=sizeof(sin);
while(1){
bzero(rbuf,sizeof(rbuf));//清空容器
if(recvfrom(sfd,rbuf,sizeof(rbuf),0,(struct sockaddr*)&sin,&addrlen)==-1)//获取传输信息
{
perror("recv");
pthread_exit(NULL);
}
int a=bianli(L,sin);//判断传入地址是否第一次加入链表
if(a==0)//是第一次
{
bzero(name,sizeof(name));//刷新容器
strcpy(name,rbuf);//复制信息
strcat(name,"上线");
list_sendto(L,sfd,name);//上线信息发送给所有在线用户
add(L,rbuf,sin);//加入在线列表
kan(L);//查看在线列表
printf("%s\n",name);//打印上线用户
}else if(a>0)//不是第一次加入
{
if(strcmp(rbuf,"quit")==0)//判断获取信息
{
if(sendto(sfd,rbuf,strlen(rbuf),0,(struct sockaddr*)&sin,sizeof(sin))==-1)//发送信息
{
perror("send");
return NULL;
}
P=find(L,sin);//获取网络地址
char brr[128]="已经下线";
bzero(name,sizeof(name));
strcpy(name,P->name);
strcat(name,brr);
list_delete(L,sin);//删除存储网络地址的节点
list_sendto(L,sfd,name);//发送给所有在线成员下线信息
kan(L);//打印在线列表
printf("%s\n",name);//打印下线用户
P=NULL;//指针清空
}else if(strcmp(rbuf,"quit")!=0)
{
Q=find(L,sin);//找到网络地址所在节点
strcpy(crr,Q->name);
strcat(crr,":");
strcat(crr,rbuf);
printf("%s\n",crr);
list_sendto(L,sfd,crr);//向在线用户发送信息
Q=NULL;
}
}
}
pthread_exit(NULL);
}
void* stak2(void*arg)
{
char wrr[128]="";
NodePtr L=(*(struct NB*)arg).L;//接收链表头结点地址
int sfd=(*(struct NB*)arg).sfd;//接受套接字符
struct sockaddr_in sin=(*(struct NB*)arg).sin;//接收网络结构体信息
char buf[128]="";
while(1)
{
strcpy(wrr,"服务器:");
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);//输入信息
buf[strlen(buf)-1]=0;
strcat(wrr,buf);
list_sendto(L,sfd,wrr);//向全体在线人员发送信息
if(strcmp(buf,"exit")==0)//判断信息内容是否关闭线程
{
tou(L);//删除链表
L=NULL;//清空指针
printf("服务器关闭\n");
break;
}
}
pthread_exit(NULL);//杀死线程
}
int main(int argc, const char *argv[])
{
NodePtr L=create();//创建链表
int sfd = socket(AF_INET,SOCK_DGRAM,0);//创建用于UDP的套接字符
if(sfd==-1)
{
perror("socket");
return -1;
}
int reuse =1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1)//设置快速重新启用端口号
{
perror("reuse");
return -1;
}
struct sockaddr_in sin;//填充信息
sin.sin_family=AF_INET;
sin.sin_port=htons(6666);
sin.sin_addr.s_addr=inet_addr("192.168.2.159");
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)//绑定信息
{
perror("bind");
return -1;
}
printf("服务器启动\n");
struct NB nb={sfd,"","",sin,L};//填充饥结构体信息
pthread_t tid1,tid2;//创建两个线程
if(pthread_create(&tid1,NULL,stak1,&nb)==-1)//传递线程1信息
{
perror("create1");
return -1;
}
if(pthread_create(&tid2,NULL,stak2,&nb)==-1)//传递线程2信息
{
perror("create1");
return -1;
}
// pthread_join(tid1,NULL);
pthread_join(tid2,NULL);//阻塞等待子线程
close(sfd);//关闭套接字
return 0;
}
#include <myhead.h>
struct NB
{
char type;
char name[20];
char text[100];
}nb;
int main(int argc, const char *argv[])
{
int zf[2];
pipe(zf);//创建无名管道通信
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd==-1)
{
perror("socket");
return -1;
}
int reuse =1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1)//设置端口号快速重启权限
{
perror("reuse");
return -1;
}
struct sockaddr_in cin;//填充信息
cin.sin_family=AF_INET;
cin.sin_port=htons(6666);
cin.sin_addr.s_addr=inet_addr("192.168.2.159");
socklen_t addrlen=sizeof(cin);
struct NB nb={0,"",""};
pid_t pid =fork();//创建子进程
if(pid>0)
{
char rbuf[128]="";
while(1)
{
bzero(rbuf,sizeof(rbuf));
if(recvfrom(sfd,rbuf,sizeof(rbuf),0,(struct sockaddr*)&cin,&addrlen)==-1)//读取网络信息
{
perror("recvfrom");
return -1;
}
if(strcmp(rbuf,"quit")==0)//判断退出条件
{
break;
}else if(strcmp(rbuf,"服务器:exit")==0)//判断服务器信息
{
pid_t bz;
read(zf[0],&bz,4);//读取管道信息
kill(bz,1);//杀死子进程
printf("服务器失去连接,强制下线\n");
break;
}
printf("%s\n",rbuf);//打印获取信息
}
}else if(pid==0)
{
pid_t pid1=getpid();//获取进程号
write(zf[1],&pid1,4);//写入管道内容
printf("请输入姓名>>>");
fgets(nb.name,sizeof(nb.name),stdin);//输入姓名内容
nb.name[strlen(nb.name)-1]=0;
if(sendto(sfd,nb.name,sizeof(nb.name),0,(struct sockaddr*)&cin,sizeof(cin))==-1)//传输网络姓名内容信息
{
perror("sendto");
return -1;
}
printf("登陆成功!\n");
while(1)
{
usleep(100);//睡眠一下让父进程先载入
bzero(nb.text,sizeof(nb.text));//刷新内容缓存
fgets(nb.text,sizeof(nb.text),stdin);//输入信息
nb.text[strlen(nb.text)-1]=0;
if(sendto(sfd,nb.text,sizeof(nb.text),0,(struct sockaddr*)&cin,sizeof(cin))==-1)//传输信息
{
perror("sendto");
return -1;
}else if(strcmp(nb.text,"quit")==0)//判断终止条件
{
printf("退出成功\n");
close(sfd);//关闭套接字字符
exit(EXIT_SUCCESS);//杀死子进程
}
printf("发送成功\n");
}
}
wait(NULL);//等待回收子进程
close(sfd);//关闭套接字符
return 0;
}