在 SFML 中使用 TcpSocket 发送数据导致分段错误
Sending data using TcpSocket in SFML causes segmentation fault
我正在使用 SFML 的 TcpSocket
class 发送和接收数据,但由于某种原因,我一直收到错误 Segmentation fault: 11
。这是服务器 class:
#include "ServerGame.hpp"
ServerGame::ServerGame()
{
}
void ServerGame::sendData(char data[3][3])
{
if (client.send(data, 9) != sf::Socket::Done)
{
//std::cout << "error" << std::endl;
}
}
void ServerGame::connect()
{
sf::TcpListener listener;
// bind the listener to a port
if (listener.listen(666) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
// accept a new connection
if (listener.accept(client) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
}
char** ServerGame::receiveData()
{
char **data;
data = new char*[3];
for(int i = 0; i < 3; ++i)
{
data[i] = new char[3];
}
std::size_t received;
// TCP socket:
if (client.receive(data, 9, received) != sf::Socket::Done)
{
// error...
}
return data;
}
这是客户class:
#include "ClientGame.hpp"
#include <iostream>
ClientGame::ClientGame()
{
}
void ClientGame::connect()
{
sf::Socket::Status status = socket.connect("127.0.0.1", 666);
if (status != sf::Socket::Done)
{
// error...
}
}
void ClientGame::sendData(char data[3][3])
{
if(socket.send(data, 9) != sf::Socket::Done)
{
//error...
}
}
char** ClientGame::receiveData()
{
char **data;
data = new char*[3];
for(int i = 0; i < 3; ++i)
{
data[i] = new char[3];
}
std::size_t received;
if (socket.receive(data, 9, received) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
return data;
}
这是启动服务器和发送数据的主要class:
#include "ServerGame.hpp"
#include "ClientGame.hpp"
int main()
{
ServerGame sg;
sg.connect();
char arr[3][3] =
{
{'a', 'b', 'c'},
{'d', 'e', 'f'},
{'g', 'h', 'i'}
};
sg.sendData(arr);
}
这是启动客户端和接收数据的主要class:
#include "ClientGame.hpp"
int main()
{
ClientGame cg;
cg.connect();
char** arr = cg.receiveData();
std:: cout << arr[0][0] << std::endl;
}
我首先编译并运行 服务器class,然后对客户端class 执行相同的操作。当我尝试访问我发送的字符数组的第一个元素时,它给出了一个分段错误。为什么会这样?
一个问题是假设 char**
与 char
的二维数组相同。它们不相同。
当你这样做时:
char **data;
data = new char*[3];
for(int i = 0; i < 3; ++i)
{
data[i] = new char[3];
}
您没有使用连续数据布局动态创建 two-dimensional char
数组,类似于 char[3][3]
。内存布局可能如下所示:
data[0] -> 0x32181000
data[1] -> 0x321A9760
data[2] -> 0x321AC980
换句话说,行散布在整个堆内存中,并且不连续。
因此当你调用这个函数时:
if (socket.receive(data, 9, received) != sf::Socket::Done)
socket.receive
函数需要一个 9 字节的连续缓冲区,但您没有提供它。 receive
函数很可能会覆盖第一行,最多 6 个字节从第一行的边缘掉落(第一行被分配为只有 3 个字节),因此溢出到导致分段的内存中错误。
我认为问题源于您试图将 two-dimensional 数组从一个函数传递到另一个函数,并使用 char**
代替实际的二维数组而犯了错误。
为了在不引入指针的情况下简化操作,创建一个包含二维 char
数组的 struct
,然后在函数之间传递此结构。
struct char2D
{
char myArray[3][3];
};
那么不用char **
,只要使用char2D
的一个实例,在需要的时候引用内部数组。
例如:
char2D ClientGame::receiveData()
{
char2D data;
std::size_t received;
if (socket.receive(&data.myArray[0][0], 9, received) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
return data;
}
然后在 main
:
int main()
{
ClientGame cg;
cg.connect();
char2D arr = cg.receiveData();
std:: cout << arr.myArray[0][0] << std::endl;
}
之所以可行,是因为 struct
是可复制和可分配的。因此,每当您按值传递内部数组并按值传递 return 时,都会复制内部数组。
我正在使用 SFML 的 TcpSocket
class 发送和接收数据,但由于某种原因,我一直收到错误 Segmentation fault: 11
。这是服务器 class:
#include "ServerGame.hpp"
ServerGame::ServerGame()
{
}
void ServerGame::sendData(char data[3][3])
{
if (client.send(data, 9) != sf::Socket::Done)
{
//std::cout << "error" << std::endl;
}
}
void ServerGame::connect()
{
sf::TcpListener listener;
// bind the listener to a port
if (listener.listen(666) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
// accept a new connection
if (listener.accept(client) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
}
char** ServerGame::receiveData()
{
char **data;
data = new char*[3];
for(int i = 0; i < 3; ++i)
{
data[i] = new char[3];
}
std::size_t received;
// TCP socket:
if (client.receive(data, 9, received) != sf::Socket::Done)
{
// error...
}
return data;
}
这是客户class:
#include "ClientGame.hpp"
#include <iostream>
ClientGame::ClientGame()
{
}
void ClientGame::connect()
{
sf::Socket::Status status = socket.connect("127.0.0.1", 666);
if (status != sf::Socket::Done)
{
// error...
}
}
void ClientGame::sendData(char data[3][3])
{
if(socket.send(data, 9) != sf::Socket::Done)
{
//error...
}
}
char** ClientGame::receiveData()
{
char **data;
data = new char*[3];
for(int i = 0; i < 3; ++i)
{
data[i] = new char[3];
}
std::size_t received;
if (socket.receive(data, 9, received) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
return data;
}
这是启动服务器和发送数据的主要class:
#include "ServerGame.hpp"
#include "ClientGame.hpp"
int main()
{
ServerGame sg;
sg.connect();
char arr[3][3] =
{
{'a', 'b', 'c'},
{'d', 'e', 'f'},
{'g', 'h', 'i'}
};
sg.sendData(arr);
}
这是启动客户端和接收数据的主要class:
#include "ClientGame.hpp"
int main()
{
ClientGame cg;
cg.connect();
char** arr = cg.receiveData();
std:: cout << arr[0][0] << std::endl;
}
我首先编译并运行 服务器class,然后对客户端class 执行相同的操作。当我尝试访问我发送的字符数组的第一个元素时,它给出了一个分段错误。为什么会这样?
一个问题是假设 char**
与 char
的二维数组相同。它们不相同。
当你这样做时:
char **data;
data = new char*[3];
for(int i = 0; i < 3; ++i)
{
data[i] = new char[3];
}
您没有使用连续数据布局动态创建 two-dimensional char
数组,类似于 char[3][3]
。内存布局可能如下所示:
data[0] -> 0x32181000
data[1] -> 0x321A9760
data[2] -> 0x321AC980
换句话说,行散布在整个堆内存中,并且不连续。
因此当你调用这个函数时:
if (socket.receive(data, 9, received) != sf::Socket::Done)
socket.receive
函数需要一个 9 字节的连续缓冲区,但您没有提供它。 receive
函数很可能会覆盖第一行,最多 6 个字节从第一行的边缘掉落(第一行被分配为只有 3 个字节),因此溢出到导致分段的内存中错误。
我认为问题源于您试图将 two-dimensional 数组从一个函数传递到另一个函数,并使用 char**
代替实际的二维数组而犯了错误。
为了在不引入指针的情况下简化操作,创建一个包含二维 char
数组的 struct
,然后在函数之间传递此结构。
struct char2D
{
char myArray[3][3];
};
那么不用char **
,只要使用char2D
的一个实例,在需要的时候引用内部数组。
例如:
char2D ClientGame::receiveData()
{
char2D data;
std::size_t received;
if (socket.receive(&data.myArray[0][0], 9, received) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
return data;
}
然后在 main
:
int main()
{
ClientGame cg;
cg.connect();
char2D arr = cg.receiveData();
std:: cout << arr.myArray[0][0] << std::endl;
}
之所以可行,是因为 struct
是可复制和可分配的。因此,每当您按值传递内部数组并按值传递 return 时,都会复制内部数组。