ARS展览项目(六)——Socket通信
本篇前提说明
因为我这边做的是表情识别,另外一边做的是贪吃蛇的动作。贪吃蛇的食物就是我的表情,所以要把两者的数据连接起来。
贪吃蛇用JAVA来做,我用C++,然后两者可以用Socket来进行数据连接。设计时候是贪吃蛇用客户端,我这边是服务端。
本项目在该文档的基础上修改,https://blog.csdn.net/qq_27923041/article/details/83857964,谢谢这位作者的帮助。
先放上代码
服务端的代码(Server端)
//#include "pch.h"
#include<iostream>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void initialization();
int main() {
//定义长度变量
int send_len = 0;
int recv_len = 0;
int len = 0;
//定义发送缓冲区和接受缓冲区
char send_buf[100];
char recv_buf[100];
//定义服务端套接字,接受请求套接字
SOCKET s_server;
SOCKET s_accept;
//服务端地址客户端地址
SOCKADDR_IN server_addr;
SOCKADDR_IN accept_addr;
initialization();
//填充服务端信息
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(5010);
//创建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0);
if (bind(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
cout << "套接字绑定失败!" << endl;
WSACleanup();
}
else {
cout << "套接字绑定成功!" << endl;
}
//设置套接字为监听状态
if (listen(s_server, SOMAXCONN) < 0) {
cout << "设置监听状态失败!" << endl;
WSACleanup();
}
else {
cout << "设置监听状态成功!" << endl;
}
cout << "服务端正在监听连接,请稍候...." << endl;
//接受连接请求
len = sizeof(SOCKADDR);
s_accept = accept(s_server, (SOCKADDR *)&accept_addr, &len);
if (s_accept == SOCKET_ERROR) {
cout << "连接失败!" << endl;
WSACleanup();
return 0;
}
cout << "连接建立,准备接受数据" << endl;
//接收数据
while (1) {
recv_len = recv(s_accept, recv_buf, 100, 0);
if (recv_len < 0) {
cout << "接受失败!" << endl;
break;
}
else {
cout << "客户端信息:" << recv_buf << endl;
}
cout << "请输入回复信息:";
cin >> send_buf;
send_len = send(s_accept, send_buf, 100, 0);
if (send_len < 0) {
cout << "发送失败!" << endl;
break;
}
}
//关闭套接字
closesocket(s_server);
closesocket(s_accept);
//释放DLL资源
WSACleanup();
return 0;
}
void initialization() {
//初始化套接字库
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0) {
cout << "初始化套接字库失败!" << endl;
}
else {
cout << "初始化套接字库成功!" << endl;
}
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
cout << "套接字库版本号不符!" << endl;
WSACleanup();
}
else {
cout << "套接字库版本正确!" << endl;
}
//填充服务端地址信息
}
客户端代码(CLient端)
//#include "pch.h"
#include<iostream>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void initialization();
int main() {
//定义长度变量
int send_len = 0;
int recv_len = 0;
//定义发送缓冲区和接受缓冲区
char send_buf[100];
char recv_buf[100];
//定义服务端套接字,接受请求套接字
SOCKET s_server;
//服务端地址客户端地址
SOCKADDR_IN server_addr;
initialization();
//填充服务端信息
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(5010);
//创建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
cout << "服务器连接失败!" << endl;
WSACleanup();
}
else {
cout << "服务器连接成功!" << endl;
}
//发送,接收数据
while (1) {
cout << "请输入发送信息:";
cin >> send_buf;
send_len = send(s_server, send_buf, 100, 0);
if (send_len < 0) {
cout << "发送失败!" << endl;
break;
}
recv_len = recv(s_server, recv_buf, 100, 0);
if (recv_len < 0) {
cout << "接受失败!" << endl;
break;
}
else {
cout << "服务端信息:" << recv_buf << endl;
}
}
//关闭套接字
closesocket(s_server);
//释放DLL资源
WSACleanup();
return 0;
}
void initialization() {
//初始化套接字库
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0) {
cout << "初始化套接字库失败!" << endl;
}
else {
cout << "初始化套接字库成功!" << endl;
}
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
cout << "套接字库版本号不符!" << endl;
WSACleanup();
}
else {
cout << "套接字库版本正确!" << endl;
}
//填充服务端地址信息
}
说明
因为我这边做的是表情识别,另外一边做的是贪吃蛇的动作。贪吃蛇的食物就是我的表情,所以要把两者的数据连接起来。
贪吃蛇用JAVA来做,我用C++,然后两者可以用Socket来进行数据连接。设计时候是贪吃蛇用客户端,我这边是服务端。
设计了:
发送数据 | 代表表情 |
---|---|
1 | 开心(happy) |
2 | 平常(common) |
3 | 厌恶(disgust) |
4 | 生气(angry) |
这里之所以放客户端的代码,我是拿来测试服务端改得好不好的,所以整个项目过程中我都没有改过客户端的代码,生成一个exe就可以一直用。
程序直接新建一个C++空项目,导入opencv和dlib属性表,加入cpp源文件就可以用。建立两个项目,一个服务端,一个客户端。
解决的一个难点
Socket通信的问题容易解决,让它改成自动发送数据也好解决,但是整合的时候发现!!Socket加入opencv或dlib的库编译时,会无法建立监听。
后来一步步排除原因,有计算机的同学帮忙,发现是socket和opencv与dlib的命名空间发生了冲突,就是using namespace stu;
不正常。
于是计算机的同学想到一个很好的方法,把Socket写在不同文件中,再写一个头文件来引用,那么两者的命名空间便不会冲突,因为是不同的cpp文件,如下:
新建一个头文件 1.h
#pragma once
#ifndef XXX_H
#define XXX_H
void aaa(int ax);
#endif
新建一个1.cpp 拿来放Socket的代码
#include "1.h"
#include<iostream>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void initialization();
extern int b_int;
void aaa(int a)
{
a = b_int;
//定义长度变量
int send_len = 0;
int recv_len = 0;
int len = 0;
//定义发送缓冲区和接受缓冲区
char send_buf[100];
char recv_buf[100];
//定义服务端套接字,接受请求套接字
SOCKET s_server;
SOCKET s_accept;
//服务端地址客户端地址
SOCKADDR_IN server_addr;
SOCKADDR_IN accept_addr;
initialization();
//填充服务端信息
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(5010);
//创建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0);
bind(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR));
//设置套接字为监听状态
listen(s_server, SOMAXCONN);
//接受连接请求
len = sizeof(SOCKADDR);
s_accept = accept(s_server, (SOCKADDR *)&accept_addr, &len);
//接收数据
while (1)
{
if (a == 1)
{
send_buf[0] = '1';
send_buf[1] = '\0';
}
else if (a == 2)
{
send_buf[0] = '2';
send_buf[1] = '\0';
}
else if (a == 3)
{
send_buf[0] = '3';
send_buf[1] = '\0';
}
else if (a == 4)
{
send_buf[0] = '4';
send_buf[1] = '\0';
}
send_len = send(s_accept, send_buf, 100, 0);
}
}
void initialization() {
//初始化套接字库
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0) {
cout << "初始化套接字库失败!" << endl;
}
else {
cout << "初始化套接字库成功!" << endl;
}
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
cout << "套接字库版本号不符!" << endl;
WSACleanup();
}
else {
cout << "套接字库版本正确!" << endl;
}
//填充服务端地址信息
}
新建一个2.cpp 拿来放main()函数
#include"1.h"
#include <iostream>
#include <thread>
#include<math.h>
using namespace std;
int b_int = 1;
extern void aaa(int a);
int main()
{
int ccc = 2 ;
b_int = ccc;
std::thread t(aaa, b_int);
t.join();
//aaa(b_int);
//cout <<b_int <<endl ;
return 0;
}
其中,std::thread t(aaa, b_int);t.join();
是多线程的动作,会在下一篇文章解释。#include <thread>
是多线程的头文件。
在这里,多文件和写库就可以了。