# 2023/3/18 UDP聊天室

2023/3/18 UDP聊天室

head.h

#ifndef __HEAD_H__
#define __HEAD_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/input.h>
#include <fcntl.h>
#include <poll.h>
#define ERR_MSG(msg) do{\
	fprintf(stderr,"line:%d\n",__LINE__);\
	perror(msg);\
}while(0);

#define MAXSIZE_NAME 20
#define MAXSIZE_DATA 1024

typedef struct 
{
	char type;
	char name[MAXSIZE_NAME];
	char text[128];
}Info;

#endif

客户端

#include "head.h"

#define SER_PORT 6666
#define SER_IP "192.168.31.59"

#define CLI_PORT 5555
#define CLI_IP "192.168.31.59"

void handler(int sig)
{
	while(waitpid(-1,NULL,WNOHANG) > 0);
}

int main(int argc, const char *argv[])
{
	__sighandler_t s = signal(SIGCHLD,handler);
	if(SIG_ERR == s)
	{
		ERR_MSG("signal");
		return -1;
	}

	//创建报式套接字
	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__);

	//填充客户器的地址信息结构体
	//真实的地址信息结构体根据地址族执行,AF_INET:man 7 ip
	struct sockaddr_in cin;
	cin.sin_family     = AF_INET;//必须填AF_INET
	//cin.sin_port       = htons(CLI_PORT);//客户端的端口号的网络字节序,1024~49151
	//cin.sin_addr.s_addr= inet_addr(CLI_IP);//IP地址,ifconfig

	if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin)) < 0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success __%d__\n",__LINE__);

	//填充服务器自身的地址信息结构体
	//给connect函数使用,指定要连接到哪个服务器
	struct sockaddr_in sin;
	sin.sin_family        = AF_INET;//必须填AF_INET
	sin.sin_port          = htons(SER_PORT);//服务器端口号的网络字节序
	sin.sin_addr.s_addr   = inet_addr(SER_IP);//服务器端IP地址的网络字节序,ifconfig
	socklen_t addrlen = sizeof(sin);

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

	while(1)
	{
		sndbuf.type = 'L';
		printf("请输入用户名:");
		scanf("%s",buf);
		while(getchar() != 10);

		strcpy(sndbuf.name,buf);
		if(sendto(cfd,&sndbuf,sizeof(sndbuf),0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
		{
			ERR_MSG("sendto");
			return -1;
		}
		sndbuf.type = 0;
		memset(sndbuf.name,0,sizeof(sndbuf.name));
		memset(sndbuf.text,0,sizeof(sndbuf.text));

		res = recvfrom(cfd,&sndbuf,sizeof(sndbuf),0,(struct sockaddr*)&sin,&addrlen);
		//res = recv(sfd,buf,sizeof(buf));
		if(res < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
		if(sndbuf.type == 'L')
		{
			if(strcmp(sndbuf.text,"login success") == 0)
			{
				printf("登陆成功\n");
				break;
			}else 
			{
				printf("不存在\n");
			}
		}
	}

	pid_t cpid = fork();

	if(cpid < 0)
	{
		ERR_MSG("fork");
		return -1;
	}else if(cpid > 0)
	{


		while(1)
		{
			memset(sndbuf.text,0,sizeof(sndbuf.text));
			sndbuf.type = 'C';

			//发送
			fgets(sndbuf.text,sizeof(sndbuf.text),stdin);
			sndbuf.text[strlen(sndbuf.text) -1] = 0;
			if(strcmp(sndbuf.text,"quit") == 0)
			{
				sndbuf.type = 'Q';
			}

			if(sendto(cfd,&sndbuf,sizeof(sndbuf),0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
			{
				ERR_MSG("sendto");
				return -1;
			}
			if(strcmp(sndbuf.text,"quit") == 0)
			{
				break;
			}

		}
		kill(cpid,9);
	}else if(0 == cpid)
	{
		while(1)
		{
			//接收数据
			sndbuf.type = 0;
			memset(sndbuf.name,0,sizeof(sndbuf.name));
			memset(sndbuf.text,0,sizeof(sndbuf.text));
			res = recvfrom(cfd,&sndbuf,sizeof(sndbuf),0,(struct sockaddr*)&sin,&addrlen);
			//res = recv(sfd,buf,sizeof(buf));
			if(res < 0)
			{
				ERR_MSG("recvfrom");
				return -1;
			}
			printf("[%s]:%s\n",sndbuf.name,sndbuf.text);
		}
		exit(0);
	}
	//关闭所有文件
	close(cfd);
	return 0;
}

服务器端

#include "head.h"

#define SER_PORT 6666
#define SER_IP "192.168.31.59"

#define CLI_PORT 5555
#define CLI_IP "192.168.31.59"

typedef struct node
{
	union{
		int len;
		struct sockaddr_in data;
	};
	struct node *next;
}*Mem,Node;
//创建头结点
Mem MemCreateHead();
//创建普通结点
Mem MemCreateNode();
//尾插
void InsertRear(Mem M,struct sockaddr_in cin);
//遍历链表
void MemShow(Mem M);
//按位置删除
int DeleteByPos(Mem M,int pos);
//按元素删除
void DeleteByName(Mem M,struct sockaddr_in cin);

void do_login(int sfd,Info rcvbuf,struct sockaddr_in cin,Mem M);

void do_chat(int sfd,Info rcvbuf,Mem M,struct sockaddr_in cin);

void do_quit(int sfd,Info rcvbuf,Mem M,struct sockaddr_in cin);

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 success sfd = %d __%d__\n",sfd,__LINE__);

	//绑定,非必须绑定
	//填充客户器的地址信息结构体
	//真实的地址信息结构体根据地址族执行,AF_INET:man 7 ip
	struct sockaddr_in cin;
	cin.sin_family     = AF_INET;//必须填AF_INET
	//cin.sin_port       = htons(CLI_PORT);//客户端的端口号的网络字节序,1024~49151
	//cin.sin_addr.s_addr= inet_addr(CLI_IP);//IP地址,ifconfig


	//填充服务器自身的地址信息结构体
	//给connect函数使用,指定要连接到哪个服务器
	struct sockaddr_in sin;
	sin.sin_family        = AF_INET;//必须填AF_INET
	sin.sin_port          = htons(SER_PORT);//服务器端口号的网络字节序
	sin.sin_addr.s_addr   = inet_addr(SER_IP);//服务器端IP地址的网络字节序,ifconfig
	socklen_t addrlen = sizeof(cin);

	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
	{
		ERR_MSG("bind");
		return -1;
	}

	printf("bind success __%d__\n",__LINE__);

	Info rcvbuf;
	ssize_t res = 0;
	char buf[128] = "";
	//struct sockaddr_in saveCin[1024-4];

	Mem M = MemCreateHead();
	if(NULL == M)
	{
		return -1;
	}



	pid_t cpid = fork();

	if(cpid < 0)
	{
		ERR_MSG("fork");
		return -1;
	}else if(cpid > 0)
	{
		while(1)
		{
			res = recvfrom(sfd,&rcvbuf,sizeof(rcvbuf),0,(struct sockaddr*)&cin,&addrlen);
			if(res < 0)
			{
				ERR_MSG("recvfrom");
				return -1;
			}

			printf("当前在线人数%d\t\n",M->len+1);
			printf("rcvbuf.name = %s :%c__%d__\n",rcvbuf.name,rcvbuf.type,__LINE__);

			switch(rcvbuf.type)
			{
			case 'L':
				//do_login
				do_login(sfd,rcvbuf,cin,M);
				break;
			case 'C':
				//do_chat
				do_chat(sfd,rcvbuf,M,cin);
				break;
			case 'Q':
				//do_quit
				do_quit(sfd,rcvbuf,M,cin);
				break;
			default:
				break;
			}
		}
		for(int i=0;i<M->len;i++)
		{
			DeleteByPos(M,1);
		}
		free(M);
		M=NULL;
	}else if(0 == cpid)
	{
		while(1)
		{
			Info note;
			note.type = 'C';
			memset(note.name,0,sizeof(note.name));
			memset(note.text,0,sizeof(note.text));
			strcpy(note.name,"通知:");
			fgets(note.text,sizeof(note.text),stdin);
			note.text[strlen(note.text) - 1] = 0;
			if(sendto(sfd,&note,sizeof(note),0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
			{
				ERR_MSG("sendto");
				return -1;
			}
		}
	}
	//关闭所有文件
	close(sfd);
	return 0;
}

void do_login(int sfd,Info rcvbuf,struct sockaddr_in cin,Mem M)
{
	//存储上线用户
	FILE* fp = fopen("./user.txt","r");
	if(NULL ==fp)
	{
		ERR_MSG("fopen");
		return;
	}
	char temp[MAXSIZE_NAME] = "";
	while(1)
	{
		memset(temp,0,sizeof(temp));
		if(fgets(temp,sizeof(temp),fp) != NULL)
		{
			temp[strlen(temp) - 1] = 0;
			if(strcmp(temp,rcvbuf.name) == 0)
			{
				InsertRear(M,cin);
				MemShow(M);
				printf("用户%s已上线\n",rcvbuf.name);
				strcpy(rcvbuf.text,"login success");
				if(sendto(sfd,&rcvbuf,sizeof(rcvbuf),0,(struct sockaddr*)&cin,sizeof(cin)) < 0)
				{
					ERR_MSG("sendto");
					return;
				}

				//通知所有人xx已上线
				memset(rcvbuf.text,0,sizeof(rcvbuf.text));
				strcpy(rcvbuf.text,"已上线");
				if(M->next)
				{
					Mem p = M->next;
					while(p)
					{
						if(p->data.sin_port != cin.sin_port)
						{
							if(sendto(sfd,&rcvbuf,sizeof(rcvbuf),0,(struct sockaddr*)&(p->data),sizeof(p->data)) < 0)
							{
								ERR_MSG("sendto");
								return;
							}
						}
						p = p->next;
					}
				}
				break;
			}
		}	
	}
	fclose(fp);


}

void do_chat(int sfd,Info rcvbuf,Mem M,struct sockaddr_in cin)
{
	Info temp = rcvbuf;
	Mem p = M->next;
	while(p)
	{
		if(p->data.sin_port != cin.sin_port)
		{
			if(sendto(sfd,&temp,sizeof(temp),0,(struct sockaddr*)&(p->data),sizeof(p->data)) < 0)
			{
				ERR_MSG("sendto");
				return;
			}
		}
			p = p->next;
	}
}

void do_quit(int sfd,Info rcvbuf,Mem M,struct sockaddr_in cin)
{
	if(strcmp(rcvbuf.text,"quit") == 0)
	{
		//通知所有人xx已上线
		memset(rcvbuf.text,0,sizeof(rcvbuf.text));
		rcvbuf.type = 'Q';
		strcpy(rcvbuf.text,"已下线");
		Mem p = M->next;
		while(p)
		{
			if(p->data.sin_port != cin.sin_port)
			{
				if(sendto(sfd,&rcvbuf,sizeof(rcvbuf),0,(struct sockaddr*)&(p->data),sizeof(p->data)) < 0)
				{
					ERR_MSG("sendto");
					return;
				}
			}
			p = p->next;
		}

		DeleteByName(M,cin);
	}

}

Mem MemCreateHead()
{
	Mem M = (Mem)malloc(sizeof(Node));
	if(NULL == M)
	{
		return NULL;
	}
	M->len = 0;
	M->next = NULL;
	return M;
}

Mem MemCreateNode()
{
	Mem p = (Mem)malloc(sizeof(Node));
	if(NULL == p)
	{
		return NULL;
	}
	p->next = NULL;
	return p;
}

void InsertRear(Mem M,struct sockaddr_in cin)
{
	Mem p = MemCreateNode();
	Mem q = M;
	if(NULL == p)
	{
		return;
	}
	while(q->next)
	{
		q = q->next;
	}
	p->data = cin;
	q->next = p;
	M->len++;
}

void MemShow(Mem M)
{
	Mem p = M;
	for(int i=0;i<M->len;i++)
	{
		p = p->next;
		printf("%d\n",ntohs(p->data.sin_port));
	}
}

int DeleteByPos(Mem M,int pos)
{
	if(M->len == 0||pos<1||pos>M->len+1)
	{
		return -1;
	}
	Mem p = M;
	for(int i=0;i<pos-1;i++)
	{
		p = p->next;
	}
	Mem q = p->next;
	p->next = q->next;
	free(q);
	q = NULL;
	M->len--;
	return 0;
}


void DeleteByName(Mem M,struct sockaddr_in cin)
{
	if(0 == M->len)
	{
		return;
	}
	Mem p = M->next;
	while(p->next)
	{
		Mem q = p->next;
		if(cin.sin_port == q->data.sin_port)
		{
			p->next = q->next;
			free(q);
			q=NULL;
			break;
		}
		p = p->next;
	}
	M->len--;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值