udp网络聊天室

 服务器

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include <stdlib.h>
#include<pthread.h>
//打印错误信息的宏函数
#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
}while(0);
typedef struct
{
	char name[20];
	char msg[128];
	int flag;
}INFO;
typedef struct Node
{
	struct sockaddr_in usr;
	struct Node *next;
}Linklist;
int sfd;
struct sockaddr_in clnt_addr;
struct sockaddr_in serv_addr;
socklen_t addrlen=sizeof(struct sockaddr_in);

Linklist *list_create()
{
	Linklist *L=(Linklist*)malloc(sizeof(Linklist));
	L->next=NULL;
	return L;
}
void login_insert(Linklist *L,int sfd,INFO info,struct sockaddr_in clnt_addr)
{
	Linklist *q=L->next;
	//遍历群发登录信息
	char buf[20]="";
	strcpy(buf,info.name);
	strcat(buf,"已登录...\n");
	while(q!=NULL)
	{
		sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&(q->usr),addrlen);
		q=q->next;
	}
	//头插
	Linklist *p =(Linklist*)malloc(sizeof(Linklist));
	if(NULL==p)
	{
		printf("节点申请失败\n");
		exit(0);
	}
	p->usr=clnt_addr;
	p->next=NULL;
	p->next=L->next;
	L->next=p;
}
void send_msg(Linklist *L,int sfd,INFO info,struct sockaddr_in clnt_addr)
{
	Linklist *q=L->next;
	char buf[200]="";
	strcat(buf,info.name);
	strcat(buf,":");
	strcat(buf,info.msg);
	buf[strlen(buf)]=0;
	while(q!=NULL)
	{
			sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&(q->usr),addrlen);
			q=q->next;
	}
}
void send_off(Linklist *L,int sfd,INFO info,struct sockaddr_in clnt_addr)
{
	Linklist *q=L->next;
	char buf[200]="";
	strcat(buf,info.name);
	strcat(buf,"已下线\n");
	while(q!=NULL)
	{
		sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&(q->usr),addrlen);
		q=q->next;
	}
	q=L->next;
	while(q->next!=NULL)
	{
		if(q->usr.sin_port == clnt_addr.sin_port && (q->usr.sin_addr.s_addr & clnt_addr.sin_addr.s_addr) == clnt_addr.sin_addr.s_addr)break;
		q=q->next;
	}
	Linklist *p=q->next;
	q->next=p->next;
	free(p);
	p=NULL;
}
void* func(void* arg)
{
	Linklist *L=(Linklist*)arg;
	while(1)
	{
		INFO info;
		if(recvfrom(sfd,&info,sizeof(info),0,(struct sockaddr*)&clnt_addr,&addrlen)<0)
		{
			ERR_MSG("recvfrom");
			exit(0);
		}
		printf("recv success\n");
		switch(info.flag)
		{
			case 1:
				{
					printf("[%s]已登录!\n",info.name);
					login_insert(L,sfd,info,clnt_addr);break;}
			case 2:
				{send_msg(L,sfd,info,clnt_addr);break;}
			case 3:
				{send_off(L,sfd,info,clnt_addr);break;}
		}
	}
}
int main(int argc, const char *argv[])
{
	if(argc<3)
	{
		fprintf(stderr,"请输入IP port\n");
		return -1;
	}
	//将获取到的端口号字符串,转换成整形
	int port =atoi(argv[2]);
	if(port<1024 || port > 49151)
	{
		fprintf(stderr,"port %d input error !! 1024~49151\n",port);
		return -1;
	}
	//创建报式套接字
	sfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sfd<0)
	{
		ERR_MSG("socket");
		return -1;
	}
	//填充服务器的IP地址以及端口号
	serv_addr.sin_family =AF_INET;
	serv_addr.sin_port =htons(port);
	serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
	//绑定服务器的地址信息结构体
	if(bind(sfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success\n");
	
	Linklist *L=list_create();
	//创建线程
	pthread_t tid;
	if(pthread_create(&tid,NULL,func,(void*)L)!=0)
	{
		perror("pthread_create");
		return -1;
	}
	while(1)
	{
		char buf[128]="";
		char msg[64]="";
		strcat(buf,"**system**");
		fgets(msg,48,stdin);
		strcat(buf,msg);
		Linklist *q=L->next;
		while(q!=NULL)
		{
			if(sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&(q->usr),(sizeof(struct sockaddr_in)))<0)
			{
				ERR_MSG("sendto");
				exit(0);
			}
			q=q->next;
		}
	}
	return 0;
}

 客户端

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include <stdlib.h>
#include<pthread.h>
//打印错误信息的宏函数
#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
}while(0);
typedef struct
{
	char name[20];
	char msg[128];
	int flag;
}INFO;
INFO info;
void *func(void *arg)
{
	pthread_detach(pthread_self());
	int sfd=*(int*)arg;
	struct sockaddr_in cin;
	socklen_t addrlen=sizeof(cin);
	char buf[200]="";
	while(1)
	{
		bzero(buf,sizeof(buf));
		if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen)<0)
		{
			ERR_MSG("recvfrom");
			break;
		}
		printf("\n");
		printf("%s\n",buf);
		printf("请输入>>>");
		fflush(stdout);
	}
}
int main(int argc, const char *argv[])
{
	if(argc<3)
	{
		fprintf(stderr,"请输入IP port\n");
		return -1;
	}
	//将获取到的端口号字符串,转换成整形
	int port =atoi(argv[2]);
	if(port<1024 || port > 49151)
	{
		fprintf(stderr,"port %d input error !! 1024~49151\n",port);
		return -1;
	}
	//创建报式套接字
	int sfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sfd<0)
	{
		ERR_MSG("socket");
		return -1;
	}
	//填充服务器的IP地址以及端口号
	struct sockaddr_in sin;
	sin.sin_family =AF_INET;
	sin.sin_port =htons(port);
	sin.sin_addr.s_addr=inet_addr(argv[1]);
	struct sockaddr_in rcv_addrmsg;
	socklen_t addrlen=sizeof(rcv_addrmsg);
	//绑定服务器的地址信息结构体-->非必须绑定

	printf("请输入姓名>>>");
	fgets(info.name,sizeof(info.name),stdin);
	info.name[strlen(info.name)-1]=0;
	info.flag=1;
	if(sendto(sfd,&info,sizeof(info),0,(struct sockaddr*)&sin,sizeof(sin))<0)
		{
			ERR_MSG("sendto");
			return -1;
		}
		printf("sendto success\n");
	//创建线程
	pthread_t tid;
	if(pthread_create(&tid,NULL,func,(void *)&sfd)!=0)
	{
		perror("pthread_create");
		return -1;
	}
	char name[20];
	strcpy(name,info.name);
	while(1)
	{
		INFO info;
		strcpy(info.name,name);
		bzero(info.msg,sizeof(info.msg));
		printf("请输入>>>");
		fgets(info.msg,sizeof(info.msg),stdin);
		info.msg[strlen(info.msg)-1]=0;
		if(strcmp(info.msg,"exit")==0)
		{
			info.flag=3;
			printf("已下线\n");
		}else
			info.flag=2;
		if(sendto(sfd,&info,sizeof(info),0,(struct sockaddr*)&sin,sizeof(sin))<0)
		{
			ERR_MSG("sendto");
			exit(0);
		}
		printf("sendto success\n");
		if(info.flag==3)
			exit(0);
	}
	return 0;
}

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值