一、实验描述:
基于TCP协议,编写面向连接的Socket通信程序,包含服务器端程序和客户端程序,实现客户端和服务器端之间的通信。
二、实验最终要达成的效果:
1.只能在Socket中使用TCP协议。
2.实现客户端和服务器阻塞状态通信。
3.首先启动服务器程序,然后启动客户端程序,当两者建立连接之后开始通信(在控制台窗口输入通信内容)。当客户端输入“quit”之后,双方通信结束。
三、实验步骤
由于课本上有面向连接的Socket编程实现步骤,且作者在代码中注入了大量注释,所以作者在这里不做过多赘述。此文章主要是为初学者(就是我)展示程序逻辑,以及为写代码不熟练的同学提供一个参考板子。
编程语言C++ 使用工具:Visual Studio 2022
服务器Server程序:
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#define BUF_SIZE 64//缓冲区大小
using namespace std;
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
char buf[BUF_SIZE];
/*-------------------------------------------------------------------------------步骤一*/
SOCKET soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//创建流式套接字
/*
if (soc == INVALID_SOCKET)
{
cout << "出错" << endl;
return 0;
}
*/
/*-------------------------------------------------------------------------------步骤二*/
//设置服务器Socket地址
sockaddr_in addr;
addr.sin_family = AF_INET;//地址家族
addr.sin_port = htons(9990);//端口
addr.sin_addr.s_addr = htonl(INADDR_ANY);//地址
//套接字soc与本地地址绑定
int error = bind(soc, (SOCKADDR*)&addr, sizeof(sockaddr_in));
//if (error == SOCKET_ERROR) cout << "出错" << endl;
/*------------------------------------------------------------------------------步骤三*/
error = listen(soc, 5);//调用监听函数
//if (error == SOCKET_ERROR) cout << "出错" << endl;
/*------------------------------------------------------------------------------步骤四*/
//接受来自客户端的请求
cout << "欢迎登录服务器..." << endl;
sockaddr_in from;//接收接入地址
int from_len = sizeof(from);//接入地址的长度
SOCKET sockAccept = accept(soc, (sockaddr *)&from, &from_len);//调用accept函数
//if (sockAccept == SOCKET_ERROR) cout << "出错" << endl;
//cout << inet_ntoa(from.sin_addr) << endl;
/*-----------------------------------------------------------------------------步骤五*/
//在服务器与客户端之间发送和接收数据
while (true)
{
ZeroMemory(buf, BUF_SIZE);
recv(sockAccept, buf, BUF_SIZE, 0);//接收客户端发送的内容
//如果客户端发送"quit"字符串,则服务器退出
if (strcmp(buf, "quit") == 0)
{
send(sockAccept, "quit", strlen("quit"), 0);
cout << "连接断开" << endl;
break;
}
cout << "新的消息:" << buf << endl;
cout << "请回复:";
//否则,向客户端发送回显字符串
string msg;
getline(cin, msg);
ZeroMemory(buf, BUF_SIZE);
strcpy(buf, msg.c_str());
send(sockAccept, buf, strlen(buf), 0);
}
WSACleanup();
//释放资源
closesocket(soc);
closesocket(sockAccept);
return 0;
}
客户端Client程序:
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#define BUF_SIZE 64
#define debug cout << "here is ok" << endl
using namespace std;
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
char buf[BUF_SIZE];
/*------------------------------------------------------步骤一*/
//创建连接到服务器的SOCKET对象
SOCKET connectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//构建地址信息
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr("172.0.0.1");//如果是在自己电脑上跑,可以使用这句
//clientService.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");//反之,写入服务器ip地址
clientService.sin_port = htons(9990);
/*-----------------------------------------------------步骤二*/
//连接到服务器
connect(connectSocket, (SOCKADDR*)&clientService, sizeof(clientService));
/*-----------------------------------------------------步骤三*/
//循环向服务器发送字符串,并显示反馈信息
cout << "欢迎登录客户端..." << endl;
while (true)
{
cout << "请发送:";
string str;
getline(cin, str);
ZeroMemory(buf, BUF_SIZE);
strcpy(buf, str.c_str());
//向服务器发送信息
send(connectSocket, buf, sizeof(buf), 0);
ZeroMemory(buf, BUF_SIZE);
recv(connectSocket, buf, sizeof(buf), 0);//接收服务器传回来的信息
if (strcmp(buf, "quit") == 0)
{
cout << "连接断开" << endl;
break;
}
cout << "新的消息:" << buf << endl;
}
closesocket(connectSocket);
WSACleanup();
return 0;
}
四、控制台通信示例: