c++Socket实现客户端与服务器数据传输
c++ Socket实现客户端与服务器数据传输
这是⾃⼰第⼆次写博客,希望在博客记录⾃⼰的学习过程,欢迎⼤家评论!
实现: 客户端往服务器端发送⼀条数据,服务器端接收数据并输出;
服务器端再发送出接收到的数据给客户端!
根据⾃⼰的脑洞,想⼀下是否可以通过的改进实现简单的QQ聊天室!
少说废话,上代码
[⽂字描述都写在注释啦,也就那么点,]
服务器实现
⼀般情况下,先实现服务端的代码,这样逻辑可能会更清晰点,主要还是看个⼈的吧!
希望不要直接copy哦,⾄少⾃⼰动⼿敲⼀敲.
#define _WINSOCK_DEPRECATED_NO_WARNINGS  //⽐较新版的vs,会警告我们不要使⽤⼀
//下旧的函数,因为提供更新更安全的函数供我们使⽤,在这呢我们
//还是⽤旧的吧,这个宏定义就是起屏蔽警告作⽤,VS下⾯也有提⽰的
#include <stdio.h>
#include <stdlib.h>
#include<iostream>
#include<string>
#include<cstring>
#include<WS2tcpip.h>
#include <WinSock2.h>      //⼀般情况下,这个头⽂件位于windows.h之前,避免发⽣某些错误
#include<Windows.h>
#pragma comment(lib, "ws2_32.lib")    //显⽰加载 ws2_32.dll ws2_32.dll就是最新socket版本啦
using namespace std;
int main()
{
cout << "-----------服务器-----------" << endl;
// 1 初始化
WSADATA wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata); //make word,你把⿏标移到WSAStartup看看参数列表,是不是就是⼀个word啊
// 2 创建服务器的套接字
SOCKET serviceSocket;
socket编程聊天室基本流程
serviceSocket = socket(AF_INET, SOCK_STREAM, 0); //socket(协议族,socket数据传输⽅式,某个协议) 我们默认为0,其实就是⼀个宏 if (SOCKET_ERROR == serviceSocket) {
cout << "套接字闯创建失败!" << endl;
}
else {
cout << "套接字创建成功!" << endl;
}
// 3 绑定套接字指定绑定的IP地址和端⼝号
sockaddr_in socketAddr;        //⼀个绑定地址:有IP地址,有端⼝号,有协议族
socketAddr.sin_family = AF_INET;
socketAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  //代码开头第⼀⾏我们定义的宏在这就其作⽤啦
socketAddr.sin_port = htons(1234);
int bRes = bind(serviceSocket, (SOCKADDR*)&socketAddr, sizeof(SOCKADDR)); //绑定注意的⼀点就是记得强制类型转换
if (SOCKET_ERROR == bRes) {
cout << "绑定失败!" << endl;
}
else {
else {
cout << "绑定成功!" << endl;
}
// 4 服务器监听
int lLen = listen(serviceSocket, 5); //监听的第⼆个参数就是:能存放多少个客户端请求,到并发编程的时候很有⽤哦 if (SOCKET_ERROR == lLen) {
cout << "监听失败!" << endl;
}
else {
cout << "监听成功!" << endl;
}
// 5 接受请求
sockaddr_in revClientAddr;
SOCKET recvClientSocket = INVALID_SOCKET; //初始化⼀个接受的客户端socket
int _revSize = sizeof(sockaddr_in);
recvClientSocket = accept(serviceSocket, (SOCKADDR*)&revClientAddr, &_revSize);
if (INVALID_SOCKET == recvClientSocket) {
cout << "服务端接受请求失败!" << endl;
}
else {
cout << "服务端接受请求成功!" << endl;
}
// 6 发送/接受数据
char recvBuf[1024] = {};
int reLen = recv(recvClientSocket, recvBuf, 1024, 0);
int sLen = send(recvClientSocket, recvBuf, reLen, 0);
if (SOCKET_ERROR == reLen) {
cout << "服务端发送数据失败" << endl;
}
else {
cout << "服务器接受到数据:    " << recvBuf << endl << endl;
}
// 7 关闭socket
closesocket(recvClientSocket);
closesocket(serviceSocket);
// 8 终⽌
WSACleanup();
cout << "服务器停⽌" << endl;
<();
return 0;
}
客户端代码实现
在这⾥再提醒⼀点,运⾏程序的时候,我们是先运⾏服务端程序,再运⾏客户端程序.
所以有些同学可能会说"我们的代码都⼀样啊!怎么到我这就不成功了呢?",这是⼀个
低级的错误,我们要避免.
还有就是我还要强调,敲代码,像我⼀样的初学者,咋不能直接copy,慢慢敲,不急!
像我写博客也⼀样,慢慢写,不慌.
乍⼀看,客户端跟服务器端代码差不多啊!
也确实是,⽽且⽐服务器端还简单,在这⾥我就不再⼀个个写注释啦,其实跟上⾯的差不多,
少废话,开始吧!
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include<iostream>
#include<string>
#include<cstring>
#include<WS2tcpip.h>
#include <WinSock2.h>
#include<Windows.h>
#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll
using namespace std;
int main()
{
cout << "-----------客户端-----------" << endl;
// 1 初始化
WSADATA wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
// 2 创建套接字
SOCKET clientSocket = {};
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
if (SOCKET_ERROR == clientSocket) {
cout << "套接字闯创建失败!" << endl;
}
else {
cout << "套接字创建成功!" << endl;
}
// 3 绑定套接字指定绑定的IP地址和端⼝号
sockaddr_in socketAddr;
socketAddr.sin_family = PF_INET;
socketAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
socketAddr.sin_port = htons(1234);
int cRes = connect(clientSocket, (SOCKADDR*)&socketAddr, sizeof(SOCKADDR)); if (SOCKET_ERROR == cRes) {
cout << "客户端:\t\t与服务器连接失败....." << endl;
}
else {
cout << "客户端:\t\t与服务器连接成功....." << endl;
}
// 4 发送请求
char sendBuf[1024] = "from Client:  hello service.";
send(clientSocket, sendBuf, strlen(sendBuf), 0);
// 5 发送/接受数据
char recvBuf[1024] = {};
recv(clientSocket, recvBuf, 1024, 0);
cout << "客户端接收数据 : " << recvBuf << endl << endl;
// 6 关闭socket
closesocket(clientSocket);
// 7 终⽌
WSACleanup();
cout << "客户端退出" << endl;
<();
<();
return 0;
}
这个就是运⾏效果啦
根据简单实现数据的发送和接受,我们⼀步⼀步改善代码
1. ⾸先使得客户端不断向服务器发送数据
发送数据: (也可以叫做请求,⼀般嘛,客户端都是向服务器端请求获得某资源).
更改代码,与上⾯⼀样,其余部分代码不做改变
服务器:
// 循环接收数据
while (true)
{
// 6 发送/接受数据
char recvBuf[4024] = {};
int reLen = recv(recvClientSocket, recvBuf, 4024, 0);
int sLen = send(recvClientSocket, recvBuf, reLen, 0);
if (SOCKET_ERROR != reLen) {
cout << "服务器接受到数据:    " << recvBuf << endl << endl;
reLen = SOCKET_ERROR;
}
}
客户端:
while (true)
{
// 4 发送请求
string s;
cout << "输⼊发送数据:  " << endl;
getline(cin, s);    //可输⼊空格,默认以换⾏符结束输⼊,
send(clientSocket, (char*)s.c_str(), s.length(), 0);
// 5 发送/接受数据
char recvBuf[4024] = {};
recv(clientSocket, recvBuf, 4024, 0);
cout << "客户端接收数据 : " << recvBuf << endl << endl;
}
提⽰:代码更改仅仅是增加⼀个while循环,思路很清晰. 客户端我们从控制台输⼊发送数据,变得更主动2.进⼀步改善,再服务器端处理简单的业务逻辑
作为学习,简单来说呢,就是获得客户端发送来的数据做⼀些处理(判断).
下⾯我们提供⼀个简单的例⼦(在服务器上做修改):
服务器:
相对于上⼀阶段,就是在while循环⾥⾯添加条件判断语句.
简单吧!
while (true)
{
// 6 发送/接受数据
char recvBuf[1024] = {};
int reLen = recv(recvClientSocket, recvBuf, 1024, 0);//阻塞函数,等待接受数据
if (SOCKET_ERROR == reLen) {
cout << "服务端发送数据失败" << endl;
}
else {
cout << "请求命令:    " << recvBuf;
if (0 == strcmp("cls", recvBuf)) {
//服务端执⾏命令
system(recvBuf);
}
/
/ 中⽂请求仅仅是为了测试可⾏性,⼀般都是⽤英⽂
else if(0 == strcmp("获取版本信息",recvBuf)) {
//返回数据
string verData = "Version: 1.0.1\nAuthor: Primer\nReleaseData: 2019-04-21";    int sLen = send(recvClientSocket, (char*)verData.c_str(), verData.length(), 0);  }
else if(0 == strcmp("exit", recvBuf)){
cout << endl << "退出服务器" << endl;
break;
}
else {
cout << "\t不正确..." << endl;
}
cout << endl;
}
}
客户端:
类似的修改,仅仅加了⼀个判断语句,不做过多的解释!
while (true)
{
// 4 发送请求
string s;
cout << "输⼊发送数据:\t";
getline(cin, s);        //可输⼊空格,默认以换⾏符结束输⼊,
send(clientSocket, (char*)s.c_str(), (int)s.length(), 0);
//因为recv接受函数是阻塞函数,所以我们加以判断
//请求正确我才接收数据,否则不影响我继续请求
if(0 == strcmp("获取版本信息", s.c_str())) {
char recvBuf[4024] = {};
int reLen = recv(clientSocket, recvBuf, 4024, 0);//阻塞函数,等待接受数据
cout << endl << recvBuf << endl << endl;
}
}
效果图:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。