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

目录

前言

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.hqwc.cn/news/412987.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RDMA编程实践-SEND-RECEICVE原语应用

RDMA编程实践 本文描述了RDMA编程过程中的SEND-RECEIVE双边原语的代码实现。包含多个版本&#xff0c;1、client向server发送消息&#xff0c;server回复client收到消息(ACK)&#xff0c;然后两边断开连接。2、server端循环等待客户端建立连接&#xff0c;client发送一次消息后…

【Android】为什么在子线程中更新UI不会抛出异常

转载请注明来源&#xff1a;https://blog.csdn.net/devnn/article/details/135638486 前言 众所周知&#xff0c;Android App在子线程中是不允许更新UI的&#xff0c;否则会抛出异常&#xff1a; android.view.ViewRootImpl$CalledFromWrongThreadException: Only the origin…

NumPy 中数组拼接、合并详解

1、np.append() 1.1、语法 将值添加到数组的末端&#xff0c;返回一个新的数组&#xff0c;而原数组不变。 numpy.append(arr, values, axisNone)参数描述arr : 类数组输入的数组values : 类数组向数组 arr 添加的元素&#xff0c;需要与 arr 维度相同axis : 整型添加操作的…

python对自动驾驶进行模拟

使用了 Pygame 库来创建一个简单的游戏环境,模拟了一辆自动驾驶汽车在道路上行驶。汽车的位置和速度通过键盘控制&#xff0c;可以左右移动和加速减速。道路的宽度和颜色可以根据需要进行调整。 import pygame import random # 游戏窗口大小 WINDOW_WIDTH 800 WINDOW_HEIG…

git 删除 submodule 子模块的步骤

实验有效&#xff0c;这里删除了两个 submodule。 1, 执行删除 submodule mkdir tmp1 && cd tmp1 && git clone --recursive ssh://gitaaa.bbb.ccc.git \ && cd ccc/ && git checkout -b abranch_01 \ && git submodule deinit -f…

我终于学会的前端技能——代码调试、打断点

在技术的世界里&#xff0c;要用魔法来打败魔法 说来惭愧我做前端已近三年了竟然还没有学会如何调试代码&#xff0c;也就是给自己的代码打上断点一步步看它的运行状态以达到理清代码运行逻辑、排查问题提升开发效率的目的。直到最近我才学会了这一技能&#xff0c;在这之前我…

Neos的渗透测试靶机练习——DarkHole-1

DarkHole-1 一、实验环境二、开始渗透1. 搜集信息2. sql注入4. 提权 三、总结 一、实验环境 虚拟机软件&#xff1a;VirtualBox 攻击机&#xff1a;kali linux&#xff08;网卡初始为仅主机模式&#xff0c;要有安全意识&#xff09; 靶机&#xff1a;DarkHole-1&#xff08;网…

磁盘位置不可用怎么修复?

磁盘位置不可用是计算机使用中经常遇到的问题。造成磁盘位置不可用的原因有多种&#xff0c;其中最常见的是磁盘文件系统损坏。当文件系统损坏时&#xff0c;操作系统无法正常访问磁盘上的数据&#xff0c;导致磁盘位置不可用。 磁盘位置不可用怎么修复&#xff1f; 当磁盘位置…

2024年北京市安全员-C3证证模拟考试题库及北京市安全员-C3证理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年北京市安全员-C3证证模拟考试题库及北京市安全员-C3证理论考试试题是由安全生产模拟考试一点通提供&#xff0c;北京市安全员-C3证证模拟考试题库是根据北京市安全员-C3证最新版教材&#xff0c;北京市安全员-C…

探索数据之美:深入Seaborn的数据可视化艺术与技巧【第26篇—python:Seaborn】

文章目录 1. 引言2. Seaborn基础2.1 安装和环境设置2.2 常用数据可视化函数2.3 设置样式和颜色主题 3. 数据准备与导入3.1 使用Pandas库加载和处理数据3.2 数据清理和缺失值处理 4. Seaborn中的常见图表4.1 折线图和散点图&#xff1a;展示趋势和变量关系4.2 条形图和箱线图&am…

个性化定制的知识付费小程序,为用户提供个性化的知识服务

明理信息科技知识付费saas租户平台 随着知识经济的兴起&#xff0c;越来越多的人开始重视知识付费&#xff0c;并希望通过打造自己的知识付费平台来实现自己的知识变现。本文将介绍如何打造自己的知识付费平台&#xff0c;并从定位、内容制作、渠道推广、运营维护四个方面进行…

Spring Boot 优雅实现统一数据返回格式+统一异常处理+统一日志处理

在我们的项目开发中&#xff0c;我们都会对数据返回格式进行统一的处理&#xff0c;这样可以方便前端人员取数据&#xff0c;当然除了正常流程的数据返回格式需要统一以外&#xff0c;我们也需要对异常的情况进行统一的处理&#xff0c;以及项目必备的日志。 1. 统一返回格式 …