网络编程day6作业

这篇具有很好参考价值的文章主要介绍了网络编程day6作业。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

完成网络聊天室编写

ser

#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
}while(0)
#define IP "127.0.0.1"
#define PORT 6666
//创建链表
Linklistptr list_create();
Linklistptr node_buy(datatype e);
int list_insert_head(Linklistptr L,datatype e);
int chat_login(Linklistptr L,int sfd,msg_t msg,datatype e);
int chat_enter(Linklistptr l,int sfd,msg_t msg,datatype e);
int chat_exit(Linklistptr L,int sfd,msg_t msg,datatype e);
typedef struct sockaddr_in datatype;//类型重命名
//创建信息结构体
typedef struct msg
{
	char type;//操作码 'L'登录 'C'群聊 'Q'退出
	char name[20];
	char text[128];
}msg_t;
//创建链表保存地址信息
typedef struct Node
{
	union
	{
		datatype res_addr;//数据域
		int len;//头结点数据域
	};
	struct Node *next;//指针域
}Node, *Linklistptr;
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\n",sfd);
	//填充接收方的地址信息结构体,给bind函数使用
	datatype sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);
	//绑定地址信息结构体
	if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success");
	//创建接收地址信息结构体
	datatype cin;
	socklen_t addrlen = sizeof(cin);
	pthread_t tid;
	msg_t msg;
	//创建一个链表
	Linklistptr L = list_create();
	if(NULL == L)
	{
		return -1;
	}
	while(1)
	{
		//主线程负责接收并处理
		if(recvfrom(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&cin, &addrlen) < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
		printf("[%s:%d] : %s\n", msg.name, ntohs(cin.sin_port), msg.text);
		switch(msg.type)
		{
		case 'L'://登录
			chat_login(L,sfd,msg,e);
			break;
		case 'C'://群聊
			chat_enter(L,sfd,msg,e);
			break;
		case 'Q'://退出
			chat_exit(L,sfd,msg,e);
			break;
		default :
			printf("输入错误\n");
			break;
		}
		info.sfd=sfd;
		info.sin=sin;
		//分支线程只负责发送系统信息
		if(pthread_create(&tid, NULL, task,(void*)&info) != 0)
		{
			fprintf(stderr, "pthread_create  failed__%d__\n",__LINE__);
			return -1;
		}
		pthread_detach(tid);
	}
	//关闭文件描述符
	if(close(sfd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}
	return 0;
}
void *task(void *arg)
{
	int sfd = ((struct Climsg*)arg)->sfd;
	datatype sin = ((struct Climsg*)arg)->sin;
	msg_t msg;
	msg.type = 'C';

	while(1)
	{

		//从终端获取消息文本
		fgets(msg.text, sizeof(msg.text), stdin);
		msg.text[strlen(msg.text)-1] = '\0';
		//将信息包名定为服务器
		strcpy(msg.name,"servce");
		if(sendto(sfd , &msg, sizeof(msg), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
		{
			ERR_MSG("sendto");
		}
	}
	close(sfd);
	pthread_exit(NULL);
}
//创建链表
Linklistptr list_create()
{
	//从堆区申请一个头结点类型
	Linklistptr L = (Linklistptr)malloc(sizeof(Node));
	if(NULL == L)
	{
		printf("创建失败\n");
		return NULL;
	}
	//创建成功后,对节点进行初始化工作
	L->len = 0;
	L->next = NULL;
	return L;
}
//申请节点封装地址信息
Linklistptr node_buy(datatype e)
{
	//在堆区申请节点
	Linklistptr p = (Linklistptr)malloc(sizeof(Node));
	if(NULL == p)
	{
		printf("申请失败]n");
		return NULL;
	}
	//节点申请成功,封装数据
	p->res_addr = e;
	p->next = NULL;
	return p;
}
//头插
int list_insert_head(Linklistptr L,datatype e)
{
	//判断逻辑
	if(NULL == L)
	{
		printf("所给链表不合法\n");
		return -1;
	}
	//调用节点封装数据
	
	Linklistptr p = node_buy(e);
	if(NULL == p)
	{
		return -1;
	}
	//头插
	p->next = L->next;
	L->next = p;
	//表长变化
	L->len++;
	return 0;
}
int chat_login(Linklistptr L,int sfd,msg_t msg,datatype e)
{
	Linklistptr p=L;//定义一个遍历指针
	while(p->next!=NULL)
	{
		p=p->next;
		if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr *)&(p->res_addr),sizeof(p->res_addr))<0)
		{
			ERR_MSG("sendto");
			return -1;
		}
	}
	//头插,将自己的地址存入链表中
	list_insert_head(L,e);
	return 0;
}
//群聊
int chat_enter(Linklistptr l,int sfd,msg_t msg,datatype e)
{
	//定义一个遍历指针
	Linklistptr p=L;
	while(p->next!=NULL)
	{
		p=p->next;
		//判断链表客户端信息
		if(memcmp(&(p->res_addr),&e,sizeof(e))==0)
		{
			if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr*)&(p->res_addr),sizeof(p->res_addr))<0)
			{
				ERR_MSG("sendto");
				return -1;
			}
		}
	}
	return 0;
}
//退出
int chat_exit(Linklistptr L,int sfd,msg_t msg,datatype e)
{
	Linklistptr p=L;
	while(p->next!=NULL)
	{	
		p=p->next;
		//判断链表客户端信息
		if(memcmp(&(p->res_addr),&e,sizeof(e))==0)
		{
			if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr*)&(p->res_addr),sizeof(p->res_addr))<0)
			{
				ERR_MSG("sendto");
				return -1;
			}
		}
		else//此时当前节点的下一个节点保存的就是要退出的成员的信息
		{
			Linklistptr q=p->next;
			if(sendto(sfd, &msg, sizeof(msg_t), 0, (struct sockaddr*)&(q->resin), sizeof(q->resin)) < 0)
			{
				ERR_MSG("sendto");
				return -1;
			}
			p->next=q->next;
			free(q);
			q=NULL;
		}
	}
	return 0;
}

cli

#include <myhead.h>
#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
}while(0)
#define IP "127.0.0.1"
#define PORT 4399
typedef struct sockaddr_in datatype;//类型重命名
//创建信息结构体
typedef struct msg
{
	char type;//操作码 'L'登录 'C'群聊 'Q'退出
	char name[20];
	char text[128];
}msg_t;

struct Climsg
{
	int cfd;
	datatype cin;
	msg_t msg;
};
void *task(void *arg);
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\n",cfd);
	//填充接收方的地址信息结构体,给sendto函数使用
	datatype sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);
	//创建接收地址信息结构体
	datatype cin;
	socklen_t c_addrlen = sizeof(cin);	
	pthread_t tid;
	msg_t msg;
	memset(&msg, 0, sizeof(msg_t));
	struct Climsg info;
	printf("请输入登录名:");
	fgets(msg.name, sizeof(msg.name), stdin);
	msg.name[strlen(msg.name)-1] = '\0';	
	msg_t msg1=msg;
	msg.type = 'L';
	strcpy(msg.text,"已进入群聊");
	//发送登录请求包
	if(sendto(cfd, &msg, sizeof(msg_t), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("sendto");
		return -1;
	}
	printf("登陆成功\n");
	info.cfd = cfd;
	info.cin = sin;
	info.msg = msg;	
	while(1)
	{
		
		memset(&msg, 0, sizeof(msg));
		if(recvfrom(cfd, &msg, sizeof(msg_t), 0, (struct sockaddr*)&cin, &c_addrlen) < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
		if(strcmp(msg.name, msg1.name) == 0)
		{
			break;
		}

		printf("[%s] : %s\n", msg.name, msg.text);


		if(pthread_create(&tid, NULL, task, (void *)&info) != 0)
		{
			ERR_MSG("pthread_create");
			return -1;
		}
	
		//将分支线程设置为分离态
		pthread_detach(tid);
		}

	//关闭套接字描述符
	close(cfd);
	return 0;
}
//线程体函数
void *task(void *arg)
{

	int cfd = ((struct Climsg*)arg)->cfd;
	datatype sin = ((struct Climsg*)arg)->cin;
	msg_t msg = ((struct Climsg*)arg)->msg;

	while(1)
	{
		//清空文本内容
		bzero(msg.text, sizeof(msg.text));
		//从终端获取数据
		fgets(msg.text, sizeof(msg.text), stdin);
		msg.text[strlen(msg.text)-1] = '\0';

		msg.type = 'C';
		if(strcmp(msg.text,"quit") == 0)
		{
			msg.type = 'Q';
			strcpy(msg.text, "已下线");
		}
		if(sendto(cfd, &msg, sizeof(msg_t), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
		{
			ERR_MSG("sendto");
		}
		if(strcmp(msg.text, "已下线") == 0)
		{
			break;
		}
	}
	close(cfd);
	pthread_exit(NULL);
}

思维导图:https://mubu.com/app/edit/home/5fnWgXpb5GT#m

网络编程day6作业,网络文章来源地址https://www.toymoban.com/news/detail-697852.html

到了这里,关于网络编程day6作业的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 作业day6

    数据库 sqlite3 sq.db 如果sq.db存在则直接打开sq.db数据库,如果不存在则先创建再打开; ​ 系统命令 需要以 . 开头,不需要以 ; 结尾 .quit 退出数据库 .exit 退出数据库 .help 显示帮助信息,获取所有系统命令; ​ .table 查看当前数据库下的所有表格; .schema 查看表的结构 创建表格c

    2024年02月20日
    浏览(42)
  • 网络编程 day 1

    1、大小端存储问题 2、思维导图  

    2024年02月11日
    浏览(35)
  • 网络编程 day 5

    1、根据select TCP服务器流程图编写服务器 2、思维导图

    2024年02月10日
    浏览(32)
  • 网络编程 day 3

    1、UDP下载 2、思维导图

    2024年02月11日
    浏览(37)
  • QT DAY6作业

    1.学生管理系统,基于QT的数据库中数据表的增删改查 头文件 源文件 修改效果图 删除效果图 2.MP4视频的灰度显示和均衡模式 源文件 效果图 3.思维导图

    2024年01月16日
    浏览(35)
  • 网络编程-day3

       UDP服务器: UDP客户端:       

    2024年02月12日
    浏览(45)
  • 网络编程day2

    TCP的基本通信 服务器端 客户端 实现机械臂控制

    2024年01月18日
    浏览(61)
  • 网络编程day1

    2024年02月01日
    浏览(51)
  • 网络编程day5

    思维导图 多路复用 selsect ser cli poll ser cli

    2024年01月22日
    浏览(41)
  • day18-网络编程(下)

    OSI的7层模型对于大家来说可能不太好理解,所以我们通过一个案例来讲解: 假设,你在浏览器上输入了一些,内部通过DNS找到对应的IP后,再发送数据时内部会做如下的事: 应用层:规定数据的格式。 表示层:对应用层数据的编码、压缩(解压缩)、分块、加密(解

    2024年04月22日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包