计算机网络课程设计-网络聊天程序的设计与实现

目录

前言

1 实验题目

2 实验目的

3 实验内容

3.1 客户端

3.1.1 步骤

3.1.2 关键代码

3.2 服务器

3.2.1 步骤

3.2.2 关键代码

4 实验结果与分析

5 代码

5.1 客户端

5.2 服务器


前言

        本实验为计算机网络课程设计内容,基本上所有代码都是根据指导书给的附录写出来的。有些实验需要实现图形界面,但是出于期末考试压力,我所有实验均是在控制台输入输出的,没有花额外时间去学习qt了,有精力的同学可以自学一下qt实现简单的图形界面。同时,该博客内容为部分报告内容,仅为大家提供参考,请勿直接抄袭。另外,本次实验所用平台是dev c++5.11

1 实验题目

        实验一 网络聊天程序的设计与实现

2 实验目的

      使用 WinSock API 的编程,了解 Socket 通信的原理,在此基础上编写一个聊天程序。

3 实验内容

3.1 客户端

3.1.1 步骤

        (1)客户端建立连接后接收服务器分配的通信套接字。

        (2)开启线程处理从服务器发送过来的数据。

        (3)不断循环,接收用户输入,发送数据到服务器。

3.1.2 关键代码

        (1)接收服务器发送的数据的线程函数

void handleRecvData(SOCKET client) {
	while(1) {
		memset(recvBuf,'\0',strlen(recvBuf));
		recvCode= recv(client,recvBuf,sizeof(recvBuf),0);
		if(recvCode==-1) {
			cout<<"接收服务器数据异常!\n";
			closesocket(client);
			WSACleanup();
			break;
		}
		if(!flag)cout<<"\n";
		cout<<recvBuf<<"\n"<<"客户端"<<name<<">";
		flag=0;
	}
}

        (2)main函数

int main() {
	// 接收服务器分配的通信套接字
	err = recv(sockClient, name, sizeof(name), 0);	
	// 开启线程处理从服务器发送过来的数据
	thread t(handleRecvData, sockClient);
	t.detach();
	// 不断循环,接收用户输入,发送数据到服务器
	while (1) {
		memset(sendBuf,'\0',strlen(sendBuf));
		cin>>sendBuf;
		flag=1;
		if(!strcmp(sendBuf,"quit")) {
			send(sockClient,"quit",strlen("quit")+1,0);
			cout<<"通知服务器客户端已关闭连接!\n";
			closesocket(sockClient);
			WSACleanup();
			break;
		}
		err = send(sockClient,sendBuf,strlen(sendBuf)+1,0);
		if(err == -1){
			cout<<"客户端发送数据失败!\n";
			break;
		} 
	}
}

3.2 服务器

3.2.1 步骤

        (1)服务器端初始化,绑定地址并开始监听客户端连接请求。

        (2)接受客户端连接请求,为每个客户端分配套接字,并加入客户端列表。

        (3)开启线程处理客户端发来的数据,同时遍历客户端列表,将接收到的信息发送给其他客户端。

3.2.2 关键代码

        (1)处理客户端主要功能代码

void handleClient(SOCKET client) {
	while(1) {
		memset(recvBuf,'\0',strlen(recvBuf));
		memset(sendBuf,'\0',strlen(sendBuf));
		recvCode= recv(client,recvBuf,sizeof(recvBuf),0);
		cout<<"recvCode :"<<recvCode<<"\n";
		if(recvCode==-1||!strcmp(recvBuf,"quit")) {
			//删除断开连接的客户端
			cout<<"客户端"<<client<<"已关闭连接!\n";
clientList.erase(remove(clientList.begin(),clientList.end(),client));
			closesocket(client);
			cout<<"删除断开连接的 client 后,clientList 包含 client 的个数:"<<clientList.size()<<"\n";
			break;
		} else {
	cout<<"clientList 包含 client 的个数:"<<clientList.size()<<"\n";
		}
		cout<<"接收到客户端"<<client<<"的数据:"<<recvBuf<<"\n";
		for(int i=0; i<clientList.size(); i++) {
			sprintf(sendBuf,"群聊信息---客户端%d>%s",client,recvBuf);
			sendCode = send(clientList[i],sendBuf,strlen(sendBuf)+1,0);
			cout<<"服务器发送数据:\""<<sendBuf<<"\",给客户端"<<clientList[i]<<",sendCode :"<<sendCode<<"\n";
		}
	}
}

        (2)main函数

int main() {
// 循环接受客户端连接请求,为每个客户端分配套接字,加入客户端列表并单独处理
while(1) {
		memset(id,'\0',strlen(id));
		cout<<"等待新客户端连接\n";
		SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
		if(sockConn==-1) {
			cout<<"新客户端连接失败\n";
			closesocket(sockConn);
			closesocket(sockSrv);
			WSACleanup();
		} else {
			cout<<"新客户端连接成功\n";
			sprintf(id,"%d",sockConn);
			sendCode = send(sockConn,id,strlen(id)+1,0);
	cout<<"为新客户端分配套接字:"<<id<<", sendCode :"<<sendCode<<"\n";
			clientList.push_back(sockConn);
			thread t(handleClient,sockConn);
			t.detach();
		}
	}

4 实验结果与分析

(1)启动服务器等待客户端连接。

图1.1 启动服务器

(2)启动3个客户端加入聊天。

图1.2 启动客户端

(3)客户端280发送消息,可以在客户端252和260收到信息。

图1.3 客户端280发送信息

5 代码

5.1 客户端

#include <stdio.h>
#include <bits/stdc++.h>
#include<iostream>
#include<string>
#include<sstream>
#include<cstdio>
#include<vector>
#include<thread>
#include <Winsock2.h>

using namespace std;

typedef long long LL;
const int maxn = 100;
const int maxRecv = 128;
const int maxSend = maxRecv + 20;

char name[6]="\0";
int flag = 0;

void handleRecvData(SOCKET client) {
	char recvBuf[maxRecv];
	int recvCode;
	while(1) {
		memset(recvBuf,'\0',strlen(recvBuf));
		recvCode= recv(client,recvBuf,sizeof(recvBuf),0);
//		cout<<"recvCode :"<<recvCode<<"\n";
		if(recvCode==-1) {
			cout<<"接收服务器数据异常!\n";
			closesocket(client);
			//shutdown(client,2);
			WSACleanup();
			break;
		}
//		cout<<"接收的的数据:"<<recvBuf;
		if(!flag)cout<<"\n";
		cout<<recvBuf;
		cout<<"\n";
		flag=0;
//		if(flag) {
//			flag=0;
//		}
//		if(!flag) {
		cout<<"客户端"<<name<<">";
//			cout<<"\n";
//		}
//		cout<<"\n请输入要发送数据:\n";
	}
}

int main() {
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD( 1, 1 );

	err = WSAStartup( wVersionRequested, &wsaData );
	if ( err != 0 ) {
		return 0;
	}
	if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {
		WSACleanup();
		return 0;
	}

	SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
	if(sockClient==-1) {
		cout<<"创建客户端失败"<<"\n";
		closesocket(sockClient);
		WSACleanup();
		return 0;
	}
	cout<<"创建客户端成功"<<"\n";

	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
	addrSrv.sin_family=AF_INET;
	addrSrv.sin_port=htons(6000);

	err = connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
	if(err==-1) {
		closesocket(sockClient);
		WSACleanup();
		cout<<"连接服务器失败"<<"\n";
	}
	cout<<"连接服务器成功\n";

	err = recv(sockClient,name,sizeof(name),0);
	if(err==-1) {
		closesocket(sockClient);
		WSACleanup();
		cout<<"获取服务器分配的通信套接字失败"<<"\n";
	}
	cout<<"服务器分配的通信套接字:"<<name<<"\n";
	cout<<"-------------------------------------------\n";

	//开启线程处理从服务器发送过来的数据
	thread t(handleRecvData,sockClient);
	t.detach();

	char sendBuf[maxSend]="\0";
	cout<<"客户端"<<name<<">";
	while(1) {
		memset(sendBuf,'\0',strlen(sendBuf));
//		cout<<"请输入要发送数据:\n";
//		cout<<"客户端"<<name<<">";
		cin>>sendBuf;
		flag=1;
		if(!strcmp(sendBuf,"quit")) {
			send(sockClient,"quit",strlen("quit")+1,0);
			cout<<"通知服务器客户端已关闭连接!\n";
			closesocket(sockClient);
			WSACleanup();
			break;
		}
		err = send(sockClient,sendBuf,strlen(sendBuf)+1,0);
//		cout<<"sendCode :"<<err<<"\n"; 
		if(err == -1){
			cout<<"客户端发送数据失败!\n";
//			closesocket(sockClient);
//			WSACleanup();
			break;
		} 
		//while(flag==1);
//		cout<<"客户端"<<name<<"发送数据:"<<sendBuf<<"\n";
//		char recvBuf[50]="\0";
//		cout<<recv(sockClient,recvBuf,50,0)<<"\n";
//		cout<<"接收到服务器数据:";
//		printf("%s\n",recvBuf);
		//cout<<closesocket(sockClient)<<"\n";
		//WSACleanup();
		//cout<<connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR))<<"\n";
		//cout<<"服务器连接成功\n";
	}
	closesocket(sockClient);
	WSACleanup();
	return 0;
}

5.2 服务器

#include <stdio.h>
#include <bits/stdc++.h>
#include<iostream>
#include<string>
#include<vector>
#include<thread>
#include <Winsock2.h>
#pragma comment(lib,"ws2_32")
using namespace std;

typedef long long LL;
const int maxn = 100;
const int maxRecv = 128;
const int maxSend = maxRecv + 20;

//SOCKET clientList[maxn];
vector<SOCKET> clientList;

void handleClient(SOCKET client) {
	char recvBuf[maxRecv]="\0";
	char sendBuf[maxSend]="\0";
	int recvCode;
	int sendCode;
	while(1) {
		memset(recvBuf,'\0',strlen(recvBuf));
		memset(sendBuf,'\0',strlen(sendBuf));
		recvCode= recv(client,recvBuf,sizeof(recvBuf),0);
		cout<<"recvCode :"<<recvCode<<"\n";
		if(recvCode==-1||!strcmp(recvBuf,"quit")) {
			//删除断开连接的客户端
			cout<<"客户端"<<client<<"已关闭连接!\n";
			clientList.erase(remove(clientList.begin(),clientList.end(),client));
			closesocket(client);
			//shutdown(client,2);
			cout<<"删除断开连接的 client 后,clientList 包含 client 的个数:"<<clientList.size()<<"\n";
			break;
		} else {
			cout<<"clientList 包含 client 的个数:"<<clientList.size()<<"\n";
		}

		cout<<"接收到客户端"<<client<<"的数据:"<<recvBuf<<"\n";
//		printf("%s\n",recvBuf);

		for(int i=0; i<clientList.size(); i++) {
//			if(clientList[i]==client) {
//				cout<<"跳过 client:"<<client<<"\n";
//				continue;
//			}
			sprintf(sendBuf,"群聊信息---客户端%d>%s",client,recvBuf);
			sendCode = send(clientList[i],sendBuf,strlen(sendBuf)+1,0);
//			sendCode = send(clientList[i],recvBuf,strlen(recvBuf)+1,0);
			cout<<"服务器发送数据:\""<<sendBuf<<"\",给客户端"<<clientList[i]<<",sendCode :"<<sendCode<<"\n";
//			cout<<"sendCode :"<<sendCode<<"\n";
		}
	}
}
int main() {
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
//	vector<SOCKET> clientList;

	wVersionRequested = MAKEWORD( 1, 1 );

	err = WSAStartup( wVersionRequested, &wsaData );
	if ( err != 0 ) {
		cout<<"初始化套接字库失败"<<"\n";
		return 0;
	}
	cout<<"初始化套接字库成功"<<"\n";
	if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {
		WSACleanup();
		cout<<"确定协议失败"<<"\n";
		return 0;
	}
	cout<<"确定协议成功"<<"\n";
	SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);
	if(sockSrv==-1) {
		closesocket(sockSrv);
		WSACleanup();
		cout<<"创建服务器失败"<<"\n";
		return 0;
	}
	cout<<"创建服务器成功"<<"\n";
	cout<<"sockSrv :"<<sockSrv<<"\n";
	SOCKADDR_IN addrSrv;
	//htonl函数把主机字节转化成网络字节的函数;u_long htonl(u_long hostlong);
	addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
	addrSrv.sin_family=AF_INET;
	addrSrv.sin_port=htons(6000);

	//绑定
	err = bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
	if(err==-1) {
		closesocket(sockSrv);
		WSACleanup();
		cout<<"服务器绑定失败"<<"\n";
		return 0;
	}
	cout<<"服务器绑定成功"<<"\n";

	err = listen(sockSrv,5);
	if(err==-1) {
		closesocket(sockSrv);
		WSACleanup();
		cout<<"监听失败"<<"\n";
		return 0;
	}
	cout<<"监听成功"<<"\n";
	cout<<"-------------------------------------------\n";
	
	SOCKADDR_IN addrClient;
	int len=sizeof(SOCKADDR);
	char id[6]="\0";
	int sendCode;
	while(1) {
		memset(id,'\0',strlen(id));
		cout<<"等待新客户端连接\n";
		SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
		if(sockConn==-1) {
			cout<<"新客户端连接失败\n";
			closesocket(sockConn);
			closesocket(sockSrv);
			WSACleanup();
		} else {
			cout<<"新客户端连接成功\n";
//			cout<<"sockConn :"<<sockConn<<"\n";
			sprintf(id,"%d",sockConn);
//			cout<<"分配给新客户端的套接字:"<<id<<"\n";
			sendCode = send(sockConn,id,strlen(id)+1,0);
			cout<<"为新客户端分配套接字:"<<id<<", sendCode :"<<sendCode<<"\n";
			clientList.push_back(sockConn);
			thread t(handleClient,sockConn);
			t.detach();
		}
//		char sendBuf[50];
		cout<<"请输入要发送数据:\n";
		cin>>sendBuf;
//		sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(addrClient.sin_addr));
//		cout<<send(sockConn,sendBuf,strlen(sendBuf)+1,0)<<"\n";
//		cout<<"服务器发送数据:"<<sendBuf<<"\n";
//		char recvBuf[50];
//		cout<<recv(sockConn,recvBuf,50,0)<<"\n";
//		if(!strcmp(recvBuf,"quit")) {
//			cout<<"客户端已关闭连接!";
//			break;
//		} else  {
//			cout<<"接收到客户端数据:";
//			printf("%s\n",recvBuf);
//		}
//		cout<<closesocket(sockConn)<<"\n";
		//cout<<"服务器关闭连接\n";
	}
	//closesocket(sockConn);
	WSACleanup();
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/332054.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1.18寒假集训

A: 解题思路&#xff1a; 这题看似很复杂&#xff0c;其实很简单&#xff0c;找规律不难发现就是输出n 1 下面是c代码&#xff1a; #include<iostream> using namespace std; int main() {int n;cin >> n;cout << n 1;return 0; } B: 解题思路&#xf…

3dmax中怎么在模型上开洞?

3dmaxS是Autodesk公司开发的基于PC系统的三维动画渲染和制作软件。我们可以使用它来做各种模型。那么怎么在模型上开洞呢&#xff1f;我们一起来看看吧&#xff01; 1、首先我们打开我们的3damx&#xff0c;这里面我使用的版本为3damxs2012,虽然版本可能各不相同。但是功能并没…

【RT-DETR有效改进】轻量级视觉变换器RepViT改进特征提取网络(轻量化网络)

前言 大家好&#xff0c;我是Snu77&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持Re…

数据库MySQL----多表查询

二、多表查询 1.创建student和score表 CREATE TABLE student ( id INT(10) NOT NULL UNIQUE PRIMARY KEY , name VARCHAR(20) NOT NULL , sex VARCHAR(4) , birth YEAR, department VARCHAR(20) , address VARCHAR(50) ); CREATE TABLE score ( id INT(10) NOT…

翻遍全网才找到的Oracle19c安装教程(Windows版)

一、下载 官方地址&#xff1a;Database Software Downloads | Oracle 中国 我下载下来了&#xff0c;有需要的可以网盘领取。 链接&#xff1a;https://pan.baidu.com/s/1-OeiuoBX3K4X7Kw7vGxdFA?pwdhssy 提取码&#xff1a;hssy 二、解压 下载下来是一个zip格式的压缩…

Java爬虫爬取图片壁纸

Java爬虫 以sougou图片为例&#xff1a;https://pic.sogou.com/ JDK17、SpringBoot3.2.X、hutool5.8.24实现Java爬虫&#xff0c;爬取页面图片 项目介绍 开发工具&#xff1a;IDEA2023.2.5 JDK&#xff1a;Java17 SpringBoot&#xff1a;3.2.x 通过 SpringBoot 快速构建开发环境…

身份验证遇到问题,登陆ChatGPT时提示:“we ran into an issue while authenticating you…”

oops&#xff01; we ran into an issue while authenticating you, if this issue persists, please contact us through our help center at help.openai.com 说明&#xff1a;哎呀&#xff01;我们在验证您的身份时遇到了一个问题&#xff0c;如果这个问题仍然存在&#xff…

Linux:shell脚本:基础使用(8)《函数局部|全局变量函数传入位置变量return》

基本的函数定义 把一些重复调用的命令写进一个函数里&#xff0c;下次直接调用函数名&#xff0c;这样的既方便修改&#xff0c;又可以让思路清晰 function 函数名(){ 当调用这个函数时候执行的命令...... } 这个是一个基础的函数定义&#xff0c;当然你不加function也是可以的…

从 GPT1 - GPT4 拆解

从 GPT1 - GPT4 拆解 从 GPT1 - GPT4GPT1&#xff1a;更适用于文本生成领域GPT2&#xff1a;扩展数据集、模型参数&#xff0c;实现一脑多用&#xff08;多个任务&#xff09;GPT3&#xff1a;元学习 大力出奇迹InstructGPT&#xff1a;指示和提示学习 人工反馈强化学习 RLHF…

实验二 体系结构

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的…

Open3D 点云转深度图像

目录 一、算法原理1、算法过程2、主要函数二、代码实现三、结果展示1、点云2、深度图像四、测试数据Open3D 点云转深度图像由CSDN点云侠原创。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。<

TypeScript 中的深拷贝和浅拷贝

什么是深拷贝 在JavaScript/TypeScript中&#xff0c;深拷贝是指创建一个对象的副本&#xff0c;而不仅仅是创建对原始对象的引用。对复制的对象进行的任何更改都不会影响原始对象&#xff0c;反之亦然。 这个副本将完全复制基础对象&#xff0c;包括每个嵌套级别的所有属性和…

在vite5和vue3开发环境中使用jodit4富文本编辑器,并添加自定义插件和使用highlight.js实现代码块高亮(附其他自定义配置项和全部代码)

最近富文本编辑器jodit终于更新发布到了4.0版本&#xff0c;加入了css变量、有更好的typescript支持&#xff0c;截止发文时的版本是&#xff1a;4.0.5&#xff0c;看到有了新版本于是便想着将本地项目中的jodit版本也进行升级&#xff0c;琢磨着再丰富和添加一些功能&#xff…

excel 各种用法

excel 各种用法 实现两张表格数据关联 vlookup 实现两张表格数据关联 vlookup 实现两个 sheet 间的关联需要用 vlookup 函数实现 函数第一个参数设置成 sheet1 中的 A 列&#xff08;如果数据很多&#xff0c;可以直接选中 A 列&#xff09; 函数的第二个参数选中 sheet2 中…

android 和 opencv 开发环境搭建

本文详细说明给android项目添加opencv库的详细步骤&#xff0c;并通过实现图片灰度化来查看配置是否成功。 下载OPENCV ANDROID SDK 到官网下载 打开 https://opencv.org/releases/ 选择android&#xff0c;下载完成后解压出下面的文件&#xff1a; 安装android sdk 和 ndk …

YOLOv8全网首发:DCNv4更快收敛、更高速度、更高性能,效果秒杀DCNv3、DCNv2等 ,助力检测

💡💡💡本文独家改进:DCNv4更快收敛、更高速度、更高性能,完美和YOLOv8结合,助力涨点 DCNv4优势:(1) 去除空间聚合中的softmax归一化,以增强其动态性和表达能力;(2) 优化存储器访问以最小化冗余操作以加速。这些改进显著加快了收敛速度,并大幅提高了处理速度,DCN…

【CSS】解决height = line-height 文字不垂直居中(偏上、偏下)的问题

解决办法1&#xff1a; 查看 font-family 属性&#xff0c;确认是否是因为字体而导致的不垂直居中问题。 其他小知识&#xff1a; 基线就是小写x字母的下边缘(线) 就是我们常说的 基线。line-height 属性设置的行高也就是定义的两行文字基线之间的距离! 参考文章&#xff1a;…

2017年认证杯SPSSPRO杯数学建模B题(第一阶段)岁月的印记全过程文档及程序

2017年认证杯SPSSPRO杯数学建模 跨年龄人脸识别模型的建立与分析 B题 岁月的印记 原题再现&#xff1a; 对同一个人来说&#xff0c;如果没有过改变面容的疾病、面部外伤或外科手术等经历&#xff0c;年轻和年老时的面容总有很大的相似性。人们在生活中也往往能够分辨出来两…

Java 方法中参数类型后写了三个点?什么意思?

1、...代表什么意思&#xff1f; 2、如何使用 3、注意事项 4、两个list&#xff0c;一个新的&#xff0c;一个旧的&#xff0c;旧列表中可能有新列表中存在的数据&#xff0c;也可能存在新列表中不存在的数据&#xff08;注&#xff1a;新旧列表中都不存在重复元素&#xff09;…

7.6 MySQL基本函数的使用(❤❤❤)

7.6 MySQL基本函数的使用 1. 提要2. 数字函数3. 字符函数3.1 替换字符3.2 左填充字符及截取字符串 4. 日期函数4.1 日期函数4.2 表达式占位符4.3 日期偏移计算4.4 日期间隔 5. 条件函数5.1 IF语句5.2 case...when语句 1. 提要 2. 数字函数 3. 字符函数 3.1 替换字符 -- INSERT…
最新文章