目錄
前言
1 實(shí)驗(yàn)題目
2 實(shí)驗(yàn)?zāi)康?/p>
3 實(shí)驗(yàn)內(nèi)容
3.1?客戶端
3.1.1 步驟
3.1.2 關(guān)鍵代碼
3.2 服務(wù)器
3.2.1 步驟
3.2.2 關(guān)鍵代碼
4 實(shí)驗(yàn)結(jié)果與分析
5 代碼
5.1 客戶端
5.2 服務(wù)器
前言
????????本實(shí)驗(yàn)為計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)內(nèi)容,基本上所有代碼都是根據(jù)指導(dǎo)書給的附錄寫出來的。有些實(shí)驗(yàn)需要實(shí)現(xiàn)圖形界面,但是出于期末考試壓力,我所有實(shí)驗(yàn)均是在控制臺(tái)輸入輸出的,沒有花額外時(shí)間去學(xué)習(xí)qt了,有精力的同學(xué)可以自學(xué)一下qt實(shí)現(xiàn)簡(jiǎn)單的圖形界面。同時(shí),該博客內(nèi)容為部分報(bào)告內(nèi)容,僅為大家提供參考,請(qǐng)勿直接抄襲。另外,本次實(shí)驗(yàn)所用平臺(tái)是dev c++5.11
1 實(shí)驗(yàn)題目
????????實(shí)驗(yàn)一 網(wǎng)絡(luò)聊天程序的設(shè)計(jì)與實(shí)現(xiàn)
2 實(shí)驗(yàn)?zāi)康?/h2>
??????使用 WinSock API 的編程,了解 Socket 通信的原理,在此基礎(chǔ)上編寫一個(gè)聊天程序。
3 實(shí)驗(yàn)內(nèi)容
3.1?客戶端
3.1.1 步驟
????????(1)客戶端建立連接后接收服務(wù)器分配的通信套接字。
????????(2)開啟線程處理從服務(wù)器發(fā)送過來的數(shù)據(jù)。
????????(3)不斷循環(huán),接收用戶輸入,發(fā)送數(shù)據(jù)到服務(wù)器。
3.1.2 關(guān)鍵代碼
????????(1)接收服務(wù)器發(fā)送的數(shù)據(jù)的線程函數(shù)
void handleRecvData(SOCKET client) {
while(1) {
memset(recvBuf,'\0',strlen(recvBuf));
recvCode= recv(client,recvBuf,sizeof(recvBuf),0);
if(recvCode==-1) {
cout<<"接收服務(wù)器數(shù)據(jù)異常!\n";
closesocket(client);
WSACleanup();
break;
}
if(!flag)cout<<"\n";
cout<<recvBuf<<"\n"<<"客戶端"<<name<<">";
flag=0;
}
}
? ? ? ? (2)main函數(shù)
int main() {
// 接收服務(wù)器分配的通信套接字
err = recv(sockClient, name, sizeof(name), 0);
// 開啟線程處理從服務(wù)器發(fā)送過來的數(shù)據(jù)
thread t(handleRecvData, sockClient);
t.detach();
// 不斷循環(huán),接收用戶輸入,發(fā)送數(shù)據(jù)到服務(wù)器
while (1) {
memset(sendBuf,'\0',strlen(sendBuf));
cin>>sendBuf;
flag=1;
if(!strcmp(sendBuf,"quit")) {
send(sockClient,"quit",strlen("quit")+1,0);
cout<<"通知服務(wù)器客戶端已關(guān)閉連接!\n";
closesocket(sockClient);
WSACleanup();
break;
}
err = send(sockClient,sendBuf,strlen(sendBuf)+1,0);
if(err == -1){
cout<<"客戶端發(fā)送數(shù)據(jù)失敗!\n";
break;
}
}
}
3.2 服務(wù)器
3.2.1 步驟
????????(1)服務(wù)器端初始化,綁定地址并開始監(jiān)聽客戶端連接請(qǐng)求。
????????(2)接受客戶端連接請(qǐng)求,為每個(gè)客戶端分配套接字,并加入客戶端列表。
????????(3)開啟線程處理客戶端發(fā)來的數(shù)據(jù),同時(shí)遍歷客戶端列表,將接收到的信息發(fā)送給其他客戶端。
3.2.2 關(guān)鍵代碼
????????(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<<"已關(guān)閉連接!\n";
clientList.erase(remove(clientList.begin(),clientList.end(),client));
closesocket(client);
cout<<"刪除斷開連接的 client 后,clientList 包含 client 的個(gè)數(shù):"<<clientList.size()<<"\n";
break;
} else {
cout<<"clientList 包含 client 的個(gè)數(shù):"<<clientList.size()<<"\n";
}
cout<<"接收到客戶端"<<client<<"的數(shù)據(jù):"<<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<<"服務(wù)器發(fā)送數(shù)據(jù):\""<<sendBuf<<"\",給客戶端"<<clientList[i]<<",sendCode :"<<sendCode<<"\n";
}
}
}
????????(2)main函數(shù)
int main() {
// 循環(huán)接受客戶端連接請(qǐng)求,為每個(gè)客戶端分配套接字,加入客戶端列表并單獨(dú)處理
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 實(shí)驗(yàn)結(jié)果與分析
(1)啟動(dòng)服務(wù)器等待客戶端連接。
圖1.1 啟動(dòng)服務(wù)器
(2)啟動(dòng)3個(gè)客戶端加入聊天。
圖1.2 啟動(dòng)客戶端
(3)客戶端280發(fā)送消息,可以在客戶端252和260收到信息。
文章來源:http://www.zghlxwxcb.cn/news/detail-802967.html
圖1.3 客戶端280發(fā)送信息文章來源地址http://www.zghlxwxcb.cn/news/detail-802967.html
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<<"接收服務(wù)器數(shù)據(jù)異常!\n";
closesocket(client);
//shutdown(client,2);
WSACleanup();
break;
}
// cout<<"接收的的數(shù)據(jù):"<<recvBuf;
if(!flag)cout<<"\n";
cout<<recvBuf;
cout<<"\n";
flag=0;
// if(flag) {
// flag=0;
// }
// if(!flag) {
cout<<"客戶端"<<name<<">";
// cout<<"\n";
// }
// cout<<"\n請(qǐng)輸入要發(fā)送數(shù)據(jù):\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<<"創(chuàng)建客戶端失敗"<<"\n";
closesocket(sockClient);
WSACleanup();
return 0;
}
cout<<"創(chuàng)建客戶端成功"<<"\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<<"連接服務(wù)器失敗"<<"\n";
}
cout<<"連接服務(wù)器成功\n";
err = recv(sockClient,name,sizeof(name),0);
if(err==-1) {
closesocket(sockClient);
WSACleanup();
cout<<"獲取服務(wù)器分配的通信套接字失敗"<<"\n";
}
cout<<"服務(wù)器分配的通信套接字:"<<name<<"\n";
cout<<"-------------------------------------------\n";
//開啟線程處理從服務(wù)器發(fā)送過來的數(shù)據(jù)
thread t(handleRecvData,sockClient);
t.detach();
char sendBuf[maxSend]="\0";
cout<<"客戶端"<<name<<">";
while(1) {
memset(sendBuf,'\0',strlen(sendBuf));
// cout<<"請(qǐng)輸入要發(fā)送數(shù)據(jù):\n";
// cout<<"客戶端"<<name<<">";
cin>>sendBuf;
flag=1;
if(!strcmp(sendBuf,"quit")) {
send(sockClient,"quit",strlen("quit")+1,0);
cout<<"通知服務(wù)器客戶端已關(guān)閉連接!\n";
closesocket(sockClient);
WSACleanup();
break;
}
err = send(sockClient,sendBuf,strlen(sendBuf)+1,0);
// cout<<"sendCode :"<<err<<"\n";
if(err == -1){
cout<<"客戶端發(fā)送數(shù)據(jù)失??!\n";
// closesocket(sockClient);
// WSACleanup();
break;
}
//while(flag==1);
// cout<<"客戶端"<<name<<"發(fā)送數(shù)據(jù):"<<sendBuf<<"\n";
// char recvBuf[50]="\0";
// cout<<recv(sockClient,recvBuf,50,0)<<"\n";
// cout<<"接收到服務(wù)器數(shù)據(jù):";
// printf("%s\n",recvBuf);
//cout<<closesocket(sockClient)<<"\n";
//WSACleanup();
//cout<<connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR))<<"\n";
//cout<<"服務(wù)器連接成功\n";
}
closesocket(sockClient);
WSACleanup();
return 0;
}
5.2 服務(wù)器
#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<<"已關(guān)閉連接!\n";
clientList.erase(remove(clientList.begin(),clientList.end(),client));
closesocket(client);
//shutdown(client,2);
cout<<"刪除斷開連接的 client 后,clientList 包含 client 的個(gè)數(shù):"<<clientList.size()<<"\n";
break;
} else {
cout<<"clientList 包含 client 的個(gè)數(shù):"<<clientList.size()<<"\n";
}
cout<<"接收到客戶端"<<client<<"的數(shù)據(jù):"<<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<<"服務(wù)器發(fā)送數(shù)據(jù):\""<<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<<"確定協(xié)議失敗"<<"\n";
return 0;
}
cout<<"確定協(xié)議成功"<<"\n";
SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);
if(sockSrv==-1) {
closesocket(sockSrv);
WSACleanup();
cout<<"創(chuàng)建服務(wù)器失敗"<<"\n";
return 0;
}
cout<<"創(chuàng)建服務(wù)器成功"<<"\n";
cout<<"sockSrv :"<<sockSrv<<"\n";
SOCKADDR_IN addrSrv;
//htonl函數(shù)把主機(jī)字節(jié)轉(zhuǎn)化成網(wǎng)絡(luò)字節(jié)的函數(shù);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<<"服務(wù)器綁定失敗"<<"\n";
return 0;
}
cout<<"服務(wù)器綁定成功"<<"\n";
err = listen(sockSrv,5);
if(err==-1) {
closesocket(sockSrv);
WSACleanup();
cout<<"監(jiān)聽失敗"<<"\n";
return 0;
}
cout<<"監(jiān)聽成功"<<"\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<<"請(qǐng)輸入要發(fā)送數(shù)據(jù):\n";
cin>>sendBuf;
// sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(addrClient.sin_addr));
// cout<<send(sockConn,sendBuf,strlen(sendBuf)+1,0)<<"\n";
// cout<<"服務(wù)器發(fā)送數(shù)據(jù):"<<sendBuf<<"\n";
// char recvBuf[50];
// cout<<recv(sockConn,recvBuf,50,0)<<"\n";
// if(!strcmp(recvBuf,"quit")) {
// cout<<"客戶端已關(guān)閉連接!";
// break;
// } else {
// cout<<"接收到客戶端數(shù)據(jù):";
// printf("%s\n",recvBuf);
// }
// cout<<closesocket(sockConn)<<"\n";
//cout<<"服務(wù)器關(guān)閉連接\n";
}
//closesocket(sockConn);
WSACleanup();
return 0;
}
到了這里,關(guān)于計(jì)算機(jī)網(wǎng)絡(luò)課程設(shè)計(jì)-網(wǎng)絡(luò)聊天程序的設(shè)計(jì)與實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!