2023年8月3日发(作者:)
c++Socket实现客户端与服务器数据传输c++ Socket实现客户端与服务器数据传输这是⾃⼰第⼆次写博客,希望在博客记录⾃⼰的学习过程,欢迎⼤家评论!实现: 客户端往服务器端发送⼀条数据,服务器端接收数据并输出;服务器端再发送出接收到的数据给客户端!根据⾃⼰的脑洞,想⼀下是否可以通过的改进实现简单的QQ聊天室!少说废话,上代码[⽂字描述都写在注释啦,也就那么点,]服务器实现⼀般情况下,先实现服务端的代码,这样逻辑可能会更清晰点,主要还是看个⼈的吧!希望不要直接copy哦,⾄少⾃⼰动⼿敲⼀敲.#define _WINSOCK_DEPRECATED_NO_WARNINGS //⽐较新版的vs,会警告我们不要使⽤⼀ //下旧的函数,因为提供更新更安全的函数供我们使⽤,在这呢我们 //还是⽤旧的吧,这个宏定义就是起屏蔽警告作⽤,VS下⾯也有提⽰的#include
cout << "套接字闯创建失败!" << endl; } else { cout << "套接字创建成功!" << endl; } // 3 绑定套接字 指定绑定的IP地址和端⼝号 sockaddr_in socketAddr; //⼀个绑定地址:有IP地址,有端⼝号,有协议族 _family = AF_INET; _addr.S_un.S_addr = inet_addr("127.0.0.1"); //代码开头第⼀⾏我们定义的宏在这就其作⽤啦 _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
} else { cout << "客户端:tt与服务器连接成功....." << 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(), (), 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.1nAuthor: PrimernReleaseData: 2019-04-21"; int sLen = send(recvClientSocket, (char*)verData.c_str(), (), 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)(), 0);
//因为recv接受函数是阻塞函数,所以我们加以判断 //请求正确我才接收数据,否则不影响我继续请求 if(0 == strcmp("获取版本信息", s.c_str())) { char recvBuf[4024] = {}; int reLen = recv(clientSocket, recvBuf, 4024, 0);//阻塞函数,等待接受数据 cout << endl << recvBuf << endl << endl; } }效果图:若要实现更多的逻辑处理,⾃⼰⼤开脑洞.3.传输结构体到服务器数据有着各种各样的类型,⽂字,图⽚,⾳频,视频等都是数据,有些数据复杂有些简单,刚开始部分我们传输的是⼀个字符型或者整型的数据到服务器上,那么这此我们传输稍微复杂⼀些的数据—结构体.…编不下去了.上代码!第⼀:在客户端和服务器端定义⼀个结构⼀致的结构体.什么叫结构⼀致?你在结构体⾥⾯定义的基本类型顺序⼀定要相同,不然在读取数据的时候,由于字节对齐不正确,可能读取出来的就是乱码 . ⾃⼰体会.我的结构体是真这样⼦的.//// 定义⼀个学⽣结构体信息typedef struct node { int id; //学号 char name[50]; //姓名 char sex[10]; //性别 int age; //年龄 char className[100]; //班级}STUDENT;服务器端:⼀样的,仅仅改动while循环部分 STUDENT student = {};//服务器接受数据,数据格式需要和客户端数据格式⼀致 while (true) { // 6 发送/接受 数据 int reLen = recv(recvClientSocket, (char*)&student, 4024, 0); if (SOCKET_ERROR != reLen){ cout << "服务端输出接受数据: " << endl << endl; cout <<"学号:t"<< << endl; cout <<"姓名:t"<< << endl; cout <<"性别:t"<< << endl; cout <<"年龄:t"<< << endl; cout <<"班级:t"<< ame << endl; memset(&student, 0, sizeof(student)); } }客户端:更简单 while (true) { // 4 发送数据 STUDENT student; cout << "输⼊学⽣信息:[学号+姓名+性别+年龄+专业班级]t"; cin >> >> >> >> >> ame; //在发送结构体的受强制转换 提供地址形式发送即可
send(clientSocket, (char*)&student, sizeof(student), 0); }效果图:
2023年8月3日发(作者:)
c++Socket实现客户端与服务器数据传输c++ Socket实现客户端与服务器数据传输这是⾃⼰第⼆次写博客,希望在博客记录⾃⼰的学习过程,欢迎⼤家评论!实现: 客户端往服务器端发送⼀条数据,服务器端接收数据并输出;服务器端再发送出接收到的数据给客户端!根据⾃⼰的脑洞,想⼀下是否可以通过的改进实现简单的QQ聊天室!少说废话,上代码[⽂字描述都写在注释啦,也就那么点,]服务器实现⼀般情况下,先实现服务端的代码,这样逻辑可能会更清晰点,主要还是看个⼈的吧!希望不要直接copy哦,⾄少⾃⼰动⼿敲⼀敲.#define _WINSOCK_DEPRECATED_NO_WARNINGS //⽐较新版的vs,会警告我们不要使⽤⼀ //下旧的函数,因为提供更新更安全的函数供我们使⽤,在这呢我们 //还是⽤旧的吧,这个宏定义就是起屏蔽警告作⽤,VS下⾯也有提⽰的#include
cout << "套接字闯创建失败!" << endl; } else { cout << "套接字创建成功!" << endl; } // 3 绑定套接字 指定绑定的IP地址和端⼝号 sockaddr_in socketAddr; //⼀个绑定地址:有IP地址,有端⼝号,有协议族 _family = AF_INET; _addr.S_un.S_addr = inet_addr("127.0.0.1"); //代码开头第⼀⾏我们定义的宏在这就其作⽤啦 _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
} else { cout << "客户端:tt与服务器连接成功....." << 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(), (), 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.1nAuthor: PrimernReleaseData: 2019-04-21"; int sLen = send(recvClientSocket, (char*)verData.c_str(), (), 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)(), 0);
//因为recv接受函数是阻塞函数,所以我们加以判断 //请求正确我才接收数据,否则不影响我继续请求 if(0 == strcmp("获取版本信息", s.c_str())) { char recvBuf[4024] = {}; int reLen = recv(clientSocket, recvBuf, 4024, 0);//阻塞函数,等待接受数据 cout << endl << recvBuf << endl << endl; } }效果图:若要实现更多的逻辑处理,⾃⼰⼤开脑洞.3.传输结构体到服务器数据有着各种各样的类型,⽂字,图⽚,⾳频,视频等都是数据,有些数据复杂有些简单,刚开始部分我们传输的是⼀个字符型或者整型的数据到服务器上,那么这此我们传输稍微复杂⼀些的数据—结构体.…编不下去了.上代码!第⼀:在客户端和服务器端定义⼀个结构⼀致的结构体.什么叫结构⼀致?你在结构体⾥⾯定义的基本类型顺序⼀定要相同,不然在读取数据的时候,由于字节对齐不正确,可能读取出来的就是乱码 . ⾃⼰体会.我的结构体是真这样⼦的.//// 定义⼀个学⽣结构体信息typedef struct node { int id; //学号 char name[50]; //姓名 char sex[10]; //性别 int age; //年龄 char className[100]; //班级}STUDENT;服务器端:⼀样的,仅仅改动while循环部分 STUDENT student = {};//服务器接受数据,数据格式需要和客户端数据格式⼀致 while (true) { // 6 发送/接受 数据 int reLen = recv(recvClientSocket, (char*)&student, 4024, 0); if (SOCKET_ERROR != reLen){ cout << "服务端输出接受数据: " << endl << endl; cout <<"学号:t"<< << endl; cout <<"姓名:t"<< << endl; cout <<"性别:t"<< << endl; cout <<"年龄:t"<< << endl; cout <<"班级:t"<< ame << endl; memset(&student, 0, sizeof(student)); } }客户端:更简单 while (true) { // 4 发送数据 STUDENT student; cout << "输⼊学⽣信息:[学号+姓名+性别+年龄+专业班级]t"; cin >> >> >> >> >> ame; //在发送结构体的受强制转换 提供地址形式发送即可
send(clientSocket, (char*)&student, sizeof(student), 0); }效果图:
发布评论