8.11网络编程

 项目:基于UDP的网络聊天室

项目需求:
1. 如果有用户登录,其他用户可以收到这个人的登录信息
2. 如果有人发送信息,其他用户可以收到这个人的群聊信息
3. 如果有人下线,其他用户可以收到这个人的下线信息
4. 服务器可以发送系统信息

服务器代码:

#include"aa.h"
#include<unistd.h>
#define IP "192.168.31.135"
pthread_t p1;
pthread_t p2;
int fp;

void*func1(void*arg)
{	
	//链表
	list* h = (list*)arg;

	//客户端
	struct sockaddr_in cin;
	socklen_t len = sizeof(cin);

	//接收客户端数据
	char buf[128] = "";

	//接收IP
    char ip[128]="";
	//接收端口号
	int num;

	while(1)
	{
		bzero(buf,sizeof(buf));
		//接收客户端消息
		if(recvfrom(fp,buf,sizeof(buf),0,(struct sockaddr*)&cin,&len)<0)
		{
			MSG("recvfrom");
			return NULL;
		}
		bzero(ip,sizeof(ip));

		//存储ip和端口号
		strcpy(ip,inet_ntoa(cin.sin_addr));
		num = ntohs(cin.sin_port);
		//printf("111\n");
		//printf("%s %d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));

		//判断该客户端是否已存在
		int flag = 0; //  flag=1存在
		list*p;
		p = h;
		while(p->next!=NULL)
		{
			p = p->next;
			if(ntohs(p->cin.sin_port) == num)
			{
				flag = 1;
				break;
			}
		}
		if(flag == 0 )
		{
			char name[50]= "";
			strcpy(name,buf);
			name[strlen(name)-18] = '\0';
			list_insert(h,num,ip,name);
			
			list *p1 = h;
			while(p1->next != NULL)
			{
				//将新加入用户信息传递给其他用户
				p1 = p1->next;
				//当前接收用户,将消息发送给其他用户
				if(ntohs(p1->cin.sin_port)!=num)
				{
					if(sendto(fp,buf,sizeof(buf),0,(struct sockaddr*)&p1->cin,sizeof(p1->cin))<0)
					{
						MSG("sendto");
						return NULL;
					}
				}
			}
		}
		
		//向其他用户传输信息
		
		//找到当前客户端用户位置
		list*pp = h;
		while(pp->next != NULL)
		{
			pp = pp->next;
			if(ntohs(pp->cin.sin_port)!=num)
				break;
		}
		
		if(flag==1)
		{
			//找到当前客户端用户位置
			list*pp = h;
			while(pp->next != NULL)
			{
				pp = pp->next;
				if(ntohs(pp->cin.sin_port)==num)
				break;
			}

			//如果客户端退出,则通知所有用户
			if(strcmp(buf,"quit")==0)
			{
				char bb[50]="";
				bzero(bb,sizeof(bb));
				strcpy(bb,pp->name);
				strcat(bb,"已退出群聊");
				list_delet(h,num); //删除用户
				list*qq = h;
				while(qq->next!=NULL)
				{
			    	qq = qq->next;
					if(sendto(fp,bb,sizeof(bb),0,(struct sockaddr*)&qq->cin,sizeof(qq->cin))<0)
					{
						MSG("sendto");
						return NULL;
					}
				}
				continue;
			}

		char buf1[128] = "";
		bzero(buf1,sizeof(buf1));
		strcpy(buf1,pp->name);
		strcat(buf1,":");
		strcat(buf1,buf);

		list*a1 = h;
		while(a1->next != NULL)
		{
			a1 = a1->next;
			//如果不是当前接收用户,则将消息发送给其他用户
			if(ntohs(a1->cin.sin_port)!=num)
			{
				if(sendto(fp,buf1,sizeof(buf1),0,(struct sockaddr*)&a1->cin,sizeof(a1->cin))<0)
				{
					MSG("sendto");
					return NULL;
				}
			}
		}
		}
	}
}

void*func2(void*arg)
{

	while(1)
	{
		list*h = (list*)arg;
		list*pp = h;
		char buf[50] = "";
		char buf1[128] = "系统消息";
		//系统消息
		scanf("%s",buf);
		while(getchar()!='\n');
		strcat(buf1,buf);

		while(pp->next!=NULL)
		{
			pp = pp->next;
			//发送客户端消息
			if(sendto(fp,buf1,sizeof(buf1),0,(struct sockaddr*)&pp->cin,sizeof(pp->cin))<0)
			{
				MSG("sendto");
				return NULL;
			}
		}
	}
}

int main(int argc, const char *argv[])
{
	fp = socket(AF_INET,SOCK_DGRAM,0);
	//创建服务器套接字
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(8888);
	sin.sin_addr.s_addr = inet_addr(IP);
	if(bind(fp,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		MSG("bind");
		return -1;
	}	
	//创建链表
	list*h = list_create();
	//创建线程
	pthread_create(&p1,NULL,func1,(void*)h);
	pthread_create(&p2,NULL,func2,(void*)h);


	pthread_join(p1,NULL);
	pthread_join(p2,NULL);
	return 0;
}

 功能函数:

#include"aa.h"

list*list_create()
{
	list*h = (list*)malloc(sizeof(list));
	h -> next = NULL;
	if(h==NULL)
	{
		printf("链表创建失败\n");
		return NULL;
	}
	return h;
}

void list_insert(list*h,int port,char*addr,char*name)
{
	//插入结点赋值
	list*temp = (list*)malloc(sizeof(list));
	strcpy(temp->name , name);
	temp->cin.sin_family = AF_INET;
	temp->cin.sin_port = htons(port);
	temp->cin.sin_addr.s_addr = inet_addr(addr);

	temp->next = h->next;
	h->next = temp;	
}

void list_delet(list*h,int port)
{
	list*temp = h;
	while(temp->next!=NULL)
	{
		if( temp->next->cin.sin_port == htons(port))
		break;
		temp = temp->next;
	}
	list*p = temp->next;
	temp->next = p->next;
	free(p);
}

 库函数:

#ifndef _pp_
#define _pp_
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<arpa/inet.h>
#include<pthread.h>
#define MSG(msg) do{\
	        printf("__%d__",__LINE__);\
	        perror(msg);\
            }while(0)

typedef struct note
{
	char name[20]; //客户端姓名
	struct sockaddr_in cin;
	//int port ;       //客户端端口号
	//char addr[128];  //客户端ip地址
	struct note* next;
}list;


//创建链表
list*list_create();

//memcmp结构体比较函数

//插入结点
void list_insert(list*h,int port,char*addr,char*name);

//删除结点
void list_delet(list*h,int port);


#endif

 客户端代码:

#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)
#define IP "192.168.31.135"
typedef struct 
{
	char addr[20];
	int port;
}msg;

pthread_t p1;
pthread_t p2;

int sfd;
msg dd;
void*func1(void*arg)
{	
	printf("请输入用户ID:");
	char name[128];
	scanf("%s",name);
	while(getchar()!='\n');
	strcat(name,"已进入聊天群");

	sendto(sfd,name,sizeof(name),0,(struct sockaddr*)arg,sizeof(*(struct sockaddr_in*)arg));

	char buf[128] = "";
	while(1)
	{
		bzero(buf, sizeof(buf));

		fgets(buf, sizeof(buf), stdin);
		buf[strlen(buf)-1] = 0;

		//将数据包发送给服务器,所以地址信息结构体需要填服务器的信息
		if(sendto(sfd, buf, sizeof(buf), 0, (struct sockaddr*)arg, sizeof(*(struct sockaddr_in*)arg)) < 0)
		{
			ERR_MSG("sendto");
			return NULL;
		}
		if(strcmp(buf,"quit")==0)
		{
			exit(0);
		}
	}
}

void*func2(void*arg)
{

	char buf[128] = "";
	    while(1)
		{
	    //接收
		bzero(buf, sizeof(buf));

		//接收服务器发送过来的数据包
		if(recvfrom(sfd, buf, sizeof(buf), 0, NULL,NULL )< 0)
		{
			ERR_MSG("recvfrom");
			return NULL;
		}
		printf("%s\n",buf);
		}
}

int main(int argc, const char *argv[])
{
	//创建服务器套接字
	sfd = socket(AF_INET,SOCK_DGRAM,0);
	//创建报式套接字
	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(8888);
	sin.sin_addr.s_addr = inet_addr(IP);

	//创建线程
	pthread_create(&p1,NULL,func1,(void*)&sin);
	pthread_create(&p2,NULL,func2,(void*)&sin);


	pthread_join(p1,NULL);
	pthread_join(p2,NULL);
	return 0;
}

结果演示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值