【网络聊天室】

该代码示例展示了如何使用UDP套接字在服务器和客户端之间进行通信。服务器监听特定IP和端口,接收客户端发送的包含类型、用户名和文本的消息,根据消息类型执行相应操作,如广播上线通知、转发消息或处理下线请求。客户端则负责登录、发送消息和接收服务器的反馈。
摘要由CSDN通过智能技术生成

只写了前两个功能。

服务器:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>



#define ERR_MSG(msg) do{\
	printf("line:%d\n",__LINE__);\
	perror(msg);\
}while(0);
#define IP "192.168.10.246"
#define PORT 6666

struct msgcli
{
  char type;
  char name[20];
  char text[128];
};

typedef struct
{
	//数据元素
	struct sockaddr_in revaddr[1024];
    struct msgcli      revmsg[1024];
	//顺序表长度
	int len;
}Seqlist;

void SeqlistDeleteBySub(Seqlist *s,int sub);

Seqlist *CreateSpce();
int main(int argc, const char *argv[])
{
	//创建流式套接字
	int sfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sfd<0)
	{
      ERR_MSG("socket");
	  return -1;
	}
	printf("socket create sucess sfd=%d __%d__\n",sfd,__LINE__);

    //允许端口快速被重用,快速复用
	int reuse =1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}

	//bind 将IP地址和端口绑定到文件描述符上
	
	//表示真实的地址信息的结构体
	struct sockaddr_in sin;
	sin.sin_family= AF_INET;    //必须填充AF_INET
	sin.sin_port  =htons(PORT); //端口的网络字节序1024~49151
	sin.sin_addr.s_addr=inet_addr(IP);  //ifconfig查看本机IP
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		ERR_MSG("bind");
		return -1;
	}


	struct sockaddr_in cin;//储存发送方的地址信息
	socklen_t addrlen=sizeof(cin);
	struct msgcli data_cli;

	int num;
   Seqlist *s=CreateSpce();
	char buf[128]="";
	ssize_t res=0;
	while(1)
	{    
		
		//清空数据包
		memset(&data_cli,0,sizeof(data_cli));
		//接收数据
		res = recvfrom(sfd, &data_cli, sizeof(data_cli), 0, (struct sockaddr*)&cin, &addrlen);
		if(res < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
		//判断数据包的内容
		if(data_cli.type=='l'||data_cli.type=='L')
		{
			printf("用户%s上线了\n",data_cli.name);
			s->revaddr[s->len]=cin;
			s->revmsg[s->len]=data_cli;
			int i=0;
			while(i<s->len)
			{
				if( sendto(sfd,&data_cli,sizeof(data_cli),0,(struct sockaddr*)&s->revaddr[i],sizeof(s->revaddr[i]))<0)
				{
					ERR_MSG("sendto");
					return -1;
				}
				i++;

			}
			s->len++;
		}
		else if(data_cli.type=='c'||data_cli.type=='C')
		{
			int i=0;
			for(;i<s->len;i++)
			{
				if(s->revaddr[i].sin_port==cin.sin_port)
				{
					break;
				}

			}

			printf("%s:%s\n", s->revmsg[i].name, data_cli.text);
			int j=0;
			while(j<s->len)
			{
				if(s->revaddr[j].sin_port!=cin.sin_port)
				{
					if( sendto(sfd,&data_cli,sizeof(data_cli),0,(struct sockaddr*)&s->revaddr[j],sizeof(s->revaddr[j]))<0)
					{
						ERR_MSG("sendto");
						return -1;
					}
				}
				j++;
			}
		}
		else if(data_cli.type=='q'||data_cli.type=='Q')
		{   
			int i;
			for(;i<s->len;i++)
			{
				if(s->revaddr[i].sin_port==cin.sin_port)
				{
					break;
				}
			}
			SeqlistDeleteBySub(s,i);

		}	
	}
	close(sfd);
	return 0;
}

Seqlist *CreateSpce()
{
	Seqlist *s=(Seqlist *)malloc(sizeof(Seqlist));
	if(s==NULL)
		return NULL;
	s->len=0;//表示顺序表数据元素的个数为0,顺序表空
	return s;
}
void SeqlistDeleteBySub(Seqlist *s,int sub)
{	
	//3,循环前移
	for(int i=sub;i<=s->len-1;i++)
	{
		s->revmsg[i]=s->revmsg[i+1];//前移
		s->revaddr[i]=s->revaddr[i+1];//前移
	}
	//4,删除了一个元素
	s->len--;
}

客户端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>

#define ERR_MSG(msg) do{\
    fprintf(stderr, "line:%d ", __LINE__);\
    perror(msg);\
}while(0)

#define PORT 6666   //1024~49151
#define IP  "192.168.10.246"     //224.0.0.0-239.255.255.255
struct msgcli
{
	char type;
	char name[20];
	char text[128];
};
int main(int argc, const char *argv[])
{
    //创建报式套接字
    int cfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(cfd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }
    printf("socket create success cfd=%d __%d__\n", cfd, __LINE__);

    //绑定--非必须绑定
    //如果不绑定,则操作系统会默认给客户端绑定本机可用IP和随机端口 


    //填充接收放的地址信息结构体,给下面的sendto函数使用
    struct sockaddr_in sin;
    sin.sin_family      = AF_INET;  //必须填充AF_INET                                 
    sin.sin_port        = htons(PORT);  //1024~49151
    sin.sin_addr.s_addr = inet_addr(IP);    //组播IP


	char buf[128] = "";
	ssize_t res = 0;

	struct sockaddr_in rcvaddr;     //存储数据包从谁哪里来
	socklen_t addrlen = sizeof(rcvaddr);
	struct msgcli data_cli;
	char c;
	printf("请登录账户:L/l 账户名\n");
	scanf(" %c",&c);
	data_cli.type=c;
	scanf("%s",data_cli.name);
	data_cli.name[strlen(data_cli.name)] = 0;
    getchar();

	printf("登录成功\n");
	//sendto将数据发送给服务器,所以需要填充服务器的地址信息结构体
	if(sendto(cfd, &data_cli, sizeof(data_cli), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("sendto");
		return -1; 
	}
   //	printf("sendto success\n");


 pid_t cpid=0;
    cpid= fork();
	if(cpid>0)
	{		
	while(1)
	{
		bzero(data_cli.text, sizeof(data_cli.text));
		//发送数据
	//	printf("%s:",data_cli.name);
		data_cli.type='c';
         //scanf(" %s",data_cli.text);
		fgets(data_cli.text, sizeof(data_cli.text), stdin);
		data_cli.text[strlen(data_cli.text)-1] = 0;

		//sendto将数据发送给服务器,所以需要填充服务器的地址信息结构体
		if(sendto(cfd, &data_cli, sizeof(data_cli), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
		{
			ERR_MSG("sendto");
			return -1;
		}
		//printf("sendto success\n");
	}
	}
	if(cpid==0) 
	{
		while(1)
		{
	//清空数据包
		memset(&data_cli,0,sizeof(data_cli));
		//接收数据
		res = recvfrom(cfd, &data_cli, sizeof(data_cli), 0, (struct sockaddr*)&sin, &addrlen);
		if(res < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
	//判断数据包的内容
		if(data_cli.type=='l'||data_cli.type=='L')
		{
			printf("用户%s上线了\n",data_cli.name);
		   
		}
		else if(data_cli.type=='c'||data_cli.type=='C')
		{
		printf("%s:%s\n",data_cli.name,data_cli.text);
						}
		else if(data_cli.type=='q'||data_cli.type=='Q')
		{
         printf("用户%s下线了\n",data_cli.name);
		}
	}
	}

	//关闭套接字
	close(cfd); 
	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值