服务器(未完成)
#include <my_head.h>
#define SER_PORT 8888
#define SER_IP "192.168.96.132"
typedef struct Msg
{
char type; //消息类型
char name[20]; //用户ID
char text[128]; //消息内容
}msg_t;
//链表节点
typedef struct node
{
struct sockaddr_in cin; //数据域:客户的网络地址信息结构体
struct node_t *next; //指针域:下一个节点的地址
}*list;
//创建头结点
list create_node()
{
list p=(list)malloc(sizeof(struct node));
if(NULL==p)
return NULL;
p->next=NULL;
return p;
}
int main(int argc, const char *argv[])
{
//创建报式套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
//创建头结点
list p=NULL;
if(sfd==-1)
{
perror("socket error");
return -1;
}
//将端口号快速重用
int reuse=-1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSERADDR,&reuse,sizeof(reuse))==-1)
{
perror("setsockopt error");
return -1;
}
//绑定服务器地址信息
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))==-1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
int res=0;
//定义客户端信息变量
struct sockaddr_in cin;
socklen_t socklen = sizeof(cin);
list p=create_node();//定义p为头结点
msg_t msg;
while(1)
{
//收到客户端来信
res=recvfrom(sfd,&msg,sizeof(msg),(struct sockaddr *)&cin,&socklen);
if(res==-1)
{
perror("recvfrom error");
return -1;
}
if(msg.type=='L')
{
//登录
login(sfd,msg,p,cin,socklen);
}
if(msg.type=="S") sendto
{
//聊天
chat(sfd,msg,p,cin);
}
if(msg.type=="Q")
{
//退出
}
else
}
//关闭套接字
close(sfd);
return 0;
}
void login(int sfd,msg_t msg,list p,struct sockaddr_in cin,socklen_t socklen)
{
//客户端登录及创建一个新的节点
list new=(list)malloc(sizeof(struct node));
while(p->next!=NULL)
{
//向所有的客户端发送某某客户端上线的消息
p=p->next;
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&cin,socklen)==-1)
{
perror("sendto error");
return -1;
}
printf("%s已上线",msg->name);
}
//将新用户信息保存 尾插到链表中
new->cin=cin;
new->next=NULL;
p->next=new;
return;
}
void chat(int sfd,msg_t msg,list p,struct sockaddr_in cin)
{
//把收到客户端的消息转发给其他所有在线客户端
while(p->next!=NULL)
{
p=p->next;
sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->cin),sizeof(p->cin));
}
}
void quit(int sfd,msg_t msg,list p,struct sockaddr_in cin)
{
//先删除下线客户端对应节点,在将下线消息发给在线客户端
while(p->next!=NULL)
{
//找到下线客户端的前一个节点
p=p->next;
sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&cin,sizeof(cin));
}
}
客户端
#include <my_head.h>
#define SER_IP "192.168.96.132"
#define SER_PORT 8888
typedef struct Msg
{
char type;
char name[20];
char text[128];
}msg_t;
int main(int argc, const char *argv[])
{
int rfd=socket(AF_INET,SOCK_DGRAM,0);
if(rfd==-1)
{
perror("socket error");
return -1;
}
//填充服务器地址信息结构体
struct sockaddr_in sin;
sin.sin_family= AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
struct sockaddr_in cin;
socklen_t socklen_cin=sizeof(cin);
msg_t msg;
msg.type='L';
printf("请输入用户名\n");
scanf("%s",msg.name);
msg.name[strlen(msg.name)-1]='\0';
//给客户端发送用户名
if(sendto(rfd,&msg,sizeof(msg),0,(struct sockaddr *)&sin,sizeof(sin))==-1)
{
perror("sendto error");
return -1;
}
pid_t pid=fork();
if(pid==0)
{
//子进程发消息
while(1)
{
scanf("%s",msg.text);
getchar();
if(strcmp(msg.text,"quit")==0)
{
msg.type=='Q';
sendto(rfd,&msg,sizeof(msg),0,(struct sockaddr *)&sin,sizeof(sin));
wait(NULL);
exit(EXIT_SUCCESS);
}
else
{
msg.type='S';
sendto(rfd,&msg,sizeof(msg),0,(struct sockaddr *)&sin,sizeof(sin));
}
}
kill(); //终止子进程运行
wait(NULL);
}
else if(pid>0)
{
//父进程接收服务端消息
while(1)
{
int res=recvfrom(rfd,&msg,sizeof(msg),0,NULL,NULL);
if(res==-1)
{
perror("recvfrom error");
return -1;
}
printf("%s:%s\n",msg.name,msg.text);
}
wait(NULL);
}
else
{
perror("fork error");
return -1;
}
close(cfd);
return 0;
}
文章描述了一个使用UDP协议的服务器程序,通过链表管理连接的客户端,支持登录、聊天和退出功能。客户端通过发送消息类型指示操作,如登录名、聊天内容或退出请求。
836

被折叠的 条评论
为什么被折叠?



