UDP网络聊天室

服务器:

#include <myhead.h>
//定义链表结构体
typedef struct Node
{
   char name[20];
   struct sockaddr_in cin;
   struct Node *next;
}node,*node_p;
//定义数据结构体
struct msgTyp
{
   char type;
   char usrname[20];
   char msgText[1024];
};
//创建头结点
node_p create_head()
{
   node_p L = (node_p)malloc(sizeof(node));
   if(L == NULL)
   {
      printf("空间申请失败\n");
	  return NULL;
   }
   L->next=NULL;
   return L;
}
//创建新结点
node_p create_node(char *name,struct sockaddr_in cin)
{
   node_p new = (node_p)malloc(sizeof(node));
   if(new == NULL)
   {
       printf("空间申请失败\n");
	   return NULL;
   }
   strcpy(new->name,name);
   new->cin = cin;
   return new;
}
//头插
void insert_head(node_p L,char *name,struct sockaddr_in cin)
{
   if(L == NULL)
   {
      printf("入参为空,请检查\n");
	  return;
   }
   node_p new = create_node(name,cin);
   new->next=L->next;
   L->next=new;
}
//按名字删除
void del(node_p L,char *name)
{
   if(L==NULL)
   {
       printf("入参为空,请检查\n");
	   return;
   }
   node_p p = L;
   while(p != NULL)
   {
       if(strcmp(p->next->name,name)==0)
	   {
          node_p del = p->next;
		  free(del);
		  p->next = p->next->next;
		  break;
	   }
	   p = p->next;
   }
}

int main(int argc, const char *argv[])
{
	//定义链表结构体变量
    node link;
	//定义数据结构体变量 
	struct msgTyp data;
	//创建链表
    node_p L = create_head();
	//创建套接字
	int sfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sfd == -1)
	{
        perror("socket error");
		return -1;
	}
	//外部传参的判断
	if(argc < 3||argc>3)
	{ 
        printf("请正确输入IP地址和端口号\n"); 
		return -1;
	}
	//端口号快速重用
    int reuse = 1;
    if(setsockopt(sfd,SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
    {
        perror("setsockopt error");
        return -1;
    }
	//绑定IP地址和端口号
	//填写服务器地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(atoi(argv[2]));
	sin.sin_addr.s_addr = inet_addr(argv[1]);
	//绑定
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
	{
        perror("bind error");
		return -1;
	}
	//定义接收对端地址信息结构体的容器
	struct sockaddr_in cin;
	socklen_t addrlen = sizeof(cin);
	//定义一个文件描述符集合
	fd_set readfds,tempfds;
	//将集合清空
	FD_ZERO(&readfds);
	//将文件描述符放入集合中
	FD_SET(0,&readfds);
	FD_SET(sfd,&readfds);
	
	int maxfd = sfd;//记录当前集合中的最大文件描述符
    while(1)
	{
       //备份
	   tempfds = readfds;
	   int res = select(maxfd+1,&tempfds,NULL,NULL,NULL);
       if(res == -1)
	   {
           perror("select error");
		   return -1;
	   }
	   else if(res == 0)
	   {
           printf("time out\n");
		   return -1;
	   }
       
	   link.cin = cin;
	   //数据的接收
	   if(FD_ISSET(sfd,&tempfds))
	   {
          recvfrom(sfd,&data,sizeof(data),0,(struct sockaddr*)&link.cin,&addrlen);
		  //登录状态
		  if(data.type == 'L')
		  {
             strcpy(link.name,data.usrname);
			 insert_head(L,link.name,link.cin);
             char arr[130] = "";
			 sprintf(arr,"----%s登录成功----",data.usrname);
			 node_p p = L->next;
			 while(p != NULL)
			 {
                 sendto(sfd,arr,sizeof(arr),0,(struct sockaddr*)&(p->cin),sizeof(p->cin));
				 p = p->next;
			 }
             printf("%s[%s %d]:登录成功:\n",link.name,inet_ntoa(link.cin.sin_addr),ntohs(link.cin.sin_port));
		  }
		  //聊天状态
		  else if(data.type == 'C')
		  {
             strcpy(link.name,data.usrname);
			 insert_head(L,link.name,link.cin);
             char brr[2000] = "";
			 sprintf(brr,"%s:%s",data.usrname,data.msgText);
			 node_p p = L->next;
			 while(p != NULL)
			 {
				 if(strcmp(p->name,msg.usrname) != 0)
				 {
                    sendto(sfd,brr,sizeof(brr),0,(struct sockaddr*)&(p->cin),sizeof(p->cin));
				 }
				 p = p->next;
			 }
             printf("%s[%s %d]:聊天成功:\n",link.name,inet_ntoa(link.cin.sin_addr),ntohs(link.cin.sin_port));
		  }
		  //退出状态
		  else if(data.type == 'Q')
		  {
             strcpy(link.name,data.usrname);
			 del(L,link.name);
             char crr[128] = "";
			 sprintf(crr,"----%s已经下线----",data.usrname);
			 node_p p = L->next;
			 while(p != NULL)
			 {
                 sendto(sfd,crr,sizeof(arr),0,(struct sockaddr*)&(p->cin),sizeof(p->cin));
				 p = p->next;
			 }
             printf("%s[%s %d]:已经下线\n",link.name,inet_ntoa(link.cin.sin_addr),ntohs(link.cin.sin_port));
		  }
	   }
       //系统发送消息
	   if(FD_ISSET(0,&tempfds))
	   {
           char sbuf[1024] = "";
		   char buf[1024] = "";
		   fgets(buf,sizeof(buf),stdin);
		   buf[sizeof(buf)-1] = 0;
		   sprintf(sbuf,"----system----:%s",buf);
		   node_p p = L->next;
		   while(p != NULL)
		   {
              sendto(sfd,sbuf,sizeof(sbuf),0,(struct sockaddr*)&(p->cin),sizeof(p->cin));
			  p = p->next;
		   }
		   printf("system[%s %d]:发送成功\n",inet_ntoa(sin.sin_addr),ntohs(sin.sin_port));
	   }
	}

	return 0;
}
#include <myhead.h>
//定义数据结构体
struct msgTyp
{
   char type;
   char usrName[20];
   char msgText[1024];
};


/*--------------主程序-------------*/
int main(int argc, const char *argv[])
{	
    struct msgTyp usr;
	//创建套接字
	int cfd = socket(AF_INET,SOCK_DGRAM,0);
	if(cfd == -1)
	{
       perror("socket error");
	   return -1;
	}
    //判断外部传参
	if(argc < 3||argc>3)
	{
       printf("请正确输入IP地址和端口号\n");
	   return -1;
	}
	//填写服务器的消息
	struct sockaddr_in sin;
    sin.sin_family = AF_INET;
	sin.sin_port = htons(atoi(argv[2]));
	sin.sin_addr.s_addr = inet_addr(argv[1]);
	socklen_t addrlen = sizeof(sin);
    //输入姓名
	char name[20] = "";
	printf("请输入姓名:");
	fgets(name,sizeof(name),stdin);
	name[strlen(name)-1] = 0;
	usr.type = 'L';
	strcpy(usr.usrName,name);
	if(sendto(cfd,&usr,sizeof(usr),0,(struct sockaddr*)&sin,sizeof(sin))==-1)
	{
        perror("sendto error");
		return -1;
	}
	//定义一个文件描述符的集合
	fd_set readfds,tempfds;
	FD_ZERO(&readfds);
	FD_SET(0,&readfds);
	FD_SET(cfd,&readfds);
	int maxfd = cfd;//纪录最大的文件描述符 
	while(1)
	{
       tempfds = readfds;
	   int res = select(maxfd+1,&tempfds,NULL,NULL,NULL);
	   if(res == -1)
	   {
           perror("select error");
		   return -1;
	   }
	   //收到客户端消息
       if(FD_ISSET(cfd,&tempfds))
	   {
           bzero(usr.msgText,sizeof(usr.msgText));
		   if(recvfrom(cfd,usr.msgText,sizeof(usr.msgText)-1,0,(struct sockaddr *)&sin,&addrlen)==-1)
		   {
               perror("recvfrom error");
			   return -1;
		   }
		   printf("%s\n",usr.msgText);
	   }
	   //发送数据
	   if(FD_ISSET(0,&tempfds))
	   {
          bzero(usr.msgText,sizeof(usr.msgText));
		  fgets(usr.msgText,sizeof(usr.msgText),stdin);
		  usr.msgText[strlen(usr.msgText)-1] = 0;

		  //退出操作
		  if(strcmp(usr.msgText,"quit")==0)
		  {
              usr.type = 'Q';
			  sendto(cfd,&usr,sizeof(usr),0,(struct sockaddr*)&sin,sizeof(sin));
			  close(cfd); 
			  return 0;
		  }
		  else
		  {
              usr.type = 'C';
			  if(sendto(cfd,&usr,sizeof(usr),0,(struct sockaddr*)&sin,sizeof(sin))==-1)
			  {
                  perror("sendto error");
				  return -1;
			  }
		  }
	   }
	}

	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值