UDP聊天室

8 篇文章 0 订阅

服务器

server.c

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
typedef struct msg
{
	char code; //L:登录 B:广播 Q:退出
	char name[32];
	char text[128];
} msg_t;
typedef struct node_t
{
	struct sockaddr_in addr;
	struct node_t *next;
} link_node_t, *link_list_t;

link_node_t *CreateLinkList();
void process_login(int sockfd, link_list_t p, msg_t msg, struct sockaddr_in caddr);
void process_chat(int sockfd, link_node_t *p, msg_t msg, struct sockaddr_in caddr);
void process_quit(int sockfd, link_list_t head, msg_t msg, struct sockaddr_in caddr);

int main(int argc, char const *argv[])
{
	int sockfd;
	struct sockaddr_in serveraddr, clientaddr;
	socklen_t len;
	char buf[128] = "";
	pid_t pid;
	msg_t msg;
	if (argc != 3)
	{
		printf("Usage:%s <ip> <port>\n", argv[0]);
		return -1;
	}
	//1.创建套接字
	sockfd = socket(AF_INET, SOCK_DGRAM, 0); //AF_INET:ipv4;SOCK_DGRAM:UDP
	if (sockfd < 0)
	{
		perror("socket error");
		return -1;
	}
	printf("socket ok.\n");
	//2.填充结构体
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(atoi(argv[2]));		 //htons:主机字节序->网络字节序
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]); //inet_addr:将argv[1]所指的字符串转换成32位的网络字节序二进制值
	len = sizeof(struct sockaddr_in);
	//3.绑定
	if (bind(sockfd, (struct sockaddr *)&serveraddr, len) < 0)
	{
		perror("bind error");
		return -1;
	}
	printf("bind ok.\n");

	if ((pid = fork()) < 0)
	{
		perror("fork error");
		return -1;
	}
	else if (pid == 0) //子进程,接收数据
	{
		link_list_t p = CreateLinkList();
		while (1)
		{
			if ((recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&clientaddr, &len)) < 0)
			{
				perror("recvfrom error");
				return -1;
			}
			switch (msg.code)
			{
			case 'L':
				process_login(sockfd, p, msg, clientaddr);
				break;
			case 'B':
				process_chat(sockfd, p, msg, clientaddr);
				break;
			case 'Q':
				process_quit(sockfd, p, msg, clientaddr);
				break;
			}
		}
	}
	else //父进程,发给子进程数据,让子进程去转发
	{
		memset(&msg, 0, sizeof(msg));
		strcpy(msg.name, "server");
		msg.code = 'B';
		while (1)
		{
			fgets(msg.text, 128, stdin);
			msg.text[strlen(msg.text) - 1] = '\0';
			sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr, len);
		}
	}
	close(sockfd);
	return 0;
}
//创建有头单向空链表
link_node_t *CreateLinkList()
{
	//molloc一个头节点
	link_list_t p = (link_list_t)malloc(sizeof(link_node_t));
	if (NULL == p)
	{
		printf("CreateLinkList error.\n");
		return NULL;
	}
	p->next = NULL;
	return p;
}
//登录函数
void process_login(int sockfd, link_list_t p, msg_t msg, struct sockaddr_in clientaddr)
{
	link_list_t pnew = p->next;
	strcpy(msg.text, msg.name);
	msg.text[strlen(msg.text)] = '\0';
	while (pnew != NULL)
	{
		sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(pnew->addr), sizeof(pnew->addr));
		pnew = pnew->next;
	}
	pnew = (link_list_t)malloc(sizeof(link_node_t));
	if (NULL == pnew)
	{
		printf("pnew malloc failed\n");
	}
	pnew->addr = clientaddr;
	pnew->next = p->next;
	p->next = pnew;
	printf("connect ip is %s  port is %d.\n", inet_ntoa((pnew->addr).sin_addr), ntohs((pnew->addr).sin_port));
	strcat(msg.text, " login.");
	puts(msg.text);
}
//聊天
void process_chat(int sockfd, link_node_t *p, msg_t msg, struct sockaddr_in clientaddr)
{
	link_list_t pnew = p->next;
	char s[128] = "";
	printf("connect ip is %s  port is %d.\n", inet_ntoa((pnew->addr).sin_addr), ntohs((pnew->addr).sin_port));
	sprintf(s, "%s said: %s", msg.name, msg.text);
	strcpy(msg.text, s);
	puts(msg.text);
	while (pnew != NULL)
	{
		if (memcmp(&clientaddr, &pnew->addr, sizeof(clientaddr)) != 0)
		{
			if (sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(pnew->addr), sizeof(pnew->addr)) < 0)
			{
				perror("fail to sendto");
			}
		}
		pnew = pnew->next;
	}
}
//客户端退出
void process_quit(int sockfd, link_list_t head, msg_t msg, struct sockaddr_in caddr)
{
	link_list_t p = head;
	link_list_t pdel = NULL;
	link_list_t pnew = p->next;
	printf("connect ip is %s  port is %d.\n", inet_ntoa((pnew->addr).sin_addr), ntohs((pnew->addr).sin_port));
	sprintf(msg.text, "%s offline.", msg.name);
	puts(msg.text);
	while (p->next)
	{
		if (memcmp(&caddr, &p->next->addr, sizeof(caddr)) == 0)
		{
			pdel = p->next;
			p->next = pdel->next;
			free(pdel);
			pdel = NULL;
		}
		else
		{
			sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->next->addr), sizeof(p->next->addr));
			p = p->next;
		}
	}
}

客户端

client.c

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

typedef struct msg
{
	char code;
	char name[32];
	char text[128];
} msg_t;

int main(int argc, char const *argv[])
{
	int sockfd;
	struct sockaddr_in serveraddr;
	socklen_t len;
	char buf[128] = "";
	msg_t msg; //保存消息
	pid_t pid;
	if (argc != 3)
	{
		printf("Usage:%s <ip> <port>\n", argv[0]);
		return -1;
	}
	//1.创建套接字
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0)
	{
		perror("socket error");
		return -1;
	}
	printf("socket ok\n");
	//2.填充结构体
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(atoi(argv[2]));
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	len = sizeof(struct sockaddr_in); //sizeof(serveraddr)   完全没区别

	printf("Input name>");
	fgets(msg.name, sizeof(msg.name), stdin);
	msg.name[strlen(msg.name) - 1] = '\0';
	msg.text[0] = '\0';
	msg.code = 'L';
	if (sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr, len) < 0)
	{
		perror("sendto error");
		return -1;
	}
	//循环收发消息,用父子进程
	pid = fork();
	if (pid < 0)
	{
		perror("fork error");
		return -1;
	}
	else if (pid == 0) //子进程
	{
		while (1)
		{
			recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr, &len);
			puts(msg.text);
		}
	}
	else
	{
		while (1)
		{
			printf("Input text>>>");
			fgets(msg.text, 128, stdin);
			msg.text[strlen(msg.text) - 1] = '\0';
			if (strcmp(msg.text, "quit") == 0)
			{
				msg.code = 'Q';
				if (sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr, len) < 0)
				{
					perror("sendto error");
					return -1;
				}
				kill(getpid(), SIGKILL);
				exit(0);
			}
			else
			{
				msg.code = 'B';
				sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr, len);
			}
		}
		wait(NULL);
	}
	close(sockfd);
	return 0;
}

Makefile

Makefile

all:
	gcc server.c -o server
	gcc client.c -o client
clean:
	rm server client
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值