#include "head.h"
//服务器端
void server_char(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr);
void server_login(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr);
void server_quit(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr);
list_t *Createlist();
int main(int argc, const char *argv[])
{
if(argc!=3){
printf("请输入IP地址 端口号\n");
return -1;
}
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd<0)
{
perror("socket error");
return -1;
}
struct sockaddr_in saddr,caddr;
saddr.sin_family=AF_INET;
saddr.sin_port=htons(atoi(argv[2]));
saddr.sin_addr.s_addr=inet_addr(argv[1]);
int len=sizeof(caddr);
if(bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr))==-1){
perror("bind error");
return -1;
}
MSG_t msg;
list_t *p=Createlist();
while(1){//接收客户端发来的结构体,判断类型,执行相应函数
recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&caddr,&len);
switch(msg.type)
{
case login:
server_login(sockfd,p,msg,caddr);
break;
case chat:
server_char(sockfd,p,msg,caddr);
break;
case quit:
server_quit(sockfd,p,msg,caddr);
break;
}
}
close(sockfd);
return 0;
}
void server_char(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr)
{
while(p->next!=NULL)
{
p=p->next;
//当前用户结点跳过不发送信息
if(memcmp(&(p->addr),&caddr,sizeof(caddr))==0){
continue;
}
//其他用户发送信息
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&(p->addr),sizeof(p->addr));
}
}
void server_login(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr)
{
sprintf(msg.text,"%s加入chat\n",msg.name);
printf("%s\n",msg.text);
while(p->next!=NULL)
{//向所有链表内用户发送上线信息
p=p->next;
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&(p->addr),sizeof(p->addr));
}
//向链表添加新用户
list_t *pnew=(list_t*)malloc(sizeof(list_t));
pnew->next=NULL;
p->next=pnew;
pnew->addr=caddr;
}
void server_quit(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr)
{
list_t *pdel=NULL;
//将离线信息写入text
sprintf(msg.text,"%s已下线\n",msg.name);
while(p->next!=NULL)
{
//找到当前用户的位置删除结点
if(memcmp(&(p->next->addr),&caddr,sizeof(caddr))==0){
pdel=p->next;
p->next=pdel->next;
free(pdel);
pdel=NULL;
}else{//非当前用户发送离线信息
p=p->next;
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&(p->addr),sizeof(p->addr));
}
}
}
list_t *Createlist()
{
list_t *p=(list_t*)malloc(sizeof(list_t));
if(p==NULL)
{
perror("malloc error");
return NULL;
}
p->next=NULL;
return p;
}
#include "head.h"
//客户端
int main(int argc, const char *argv[])
{
if(argc!=3){
printf("请输入IP地址 端口号\n");
return -1;
}
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd==-1){
perror("socket error");
return -1;
}
struct sockaddr_in caddr;
caddr.sin_family=AF_INET;
caddr.sin_port=htons(atoi(argv[2]));
caddr.sin_addr.s_addr=inet_addr(argv[1]);
MSG_t msg;
printf("请输入用户名:");
fgets(msg.name,sizeof(msg.name),stdin);
if(msg.name[strlen(msg.name)-1]=='\n'){
msg.name[strlen(msg.name)-1]='\0';
}
msg.type=login;//发送用户名和登录类型的结构体到服务器
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&caddr,sizeof(caddr));
pid_t pid=fork();
if(pid<0){
perror("fork error");
return -1;
}else if(pid==0){//子进程接收服务器返回的结构体消息
while(1){
recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL);
printf("%s:%s\n",msg.name,msg.text);
}
}else{//父进程向服务器发送结构体类型消息
while(1){
//向结构text写内容
fgets(msg.text,sizeof(msg.text),stdin);
if(msg.text[strlen(msg.text)-1]=='\n'){
msg.text[strlen(msg.text)-1]='\0';
}//在输入内容后添加\0
//输入quit跳出循环下线
if(strncmp(msg.text,"quit",4)==0){
msg.type=quit;
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&caddr,sizeof(caddr));
break;
}else{//非quit正常聊天
msg.type=chat;
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&caddr,sizeof(caddr));
}
}
kill(pid,SIGKILL);//循环结束说明用户下线杀死子进程
wait(NULL);
}
close(sockfd);
return 0;
}
#include <myhead.h>
//重定向list_t用户地址端口链表
typedef struct node
{
struct sockaddr_in addr;
struct node *next;
}list_t;
//重定向MSG_t信息结构体
typedef struct msg_t
{
int type;
char name[32];
char text[128];
}MSG_t;
//定义枚举变量
enum type_t
{
login,
chat,
quit,
};