通过 Winsock 发送键盘缓冲区
现在我是 WINSOCK 的新手,并且不太精通 C++,所以请耐心等待。我编写了一个 NetworkServer 和 NetworkClient 类,主要基于 MSDN 教程。客户端将向服务器发送一个大小为 256 的字符数组,其中包含每个标准键盘按钮的状态(0 表示该键未被按下,1 表示该键被按下)。
运行代码时,我首先启动服务器,然后启动客户端。他们彼此连接得很好。然后调用客户端发送键盘缓冲区。缓冲区已发送,但服务器在以下情况后挂起:
receiveResult = recv(theClient, buffer, sizeof(buffer), 0);
每个类中的“keys”变量是一个字符键[256],用于保存每个键状态。
下面是 NetworkServer 启动后发生的循环:
char buffer[256];
int receiveResult, sendResult;
// Receive from the client
do
{
receiveResult = recv(theClient, buffer, sizeof(buffer), 0);
if (receiveResult > 0 )
{
sendResult = send(theClient, buffer, receiveResult, 0);
if (sendResult == SOCKET_ERROR)
{
sendResult = WSAGetLastError();
JBS::reportSocketError(nret, "server send()");
closesocket(theClient);
WSACleanup();
return;
}
else
{
memcpy(keys, buffer, sizeof(keys));
}
}
else if (receiveResult == 0)
cout << "Server closing." << endl;
else
{
receiveResult = WSAGetLastError();
JBS::reportSocketError(nret, "server receive()");
closesocket(theClient);
WSACleanup();
return;
}
} while (receiveResult > 0);
这是 NetworkClient 发送方法:
char buffer[256];
memcpy(buffer, keys, sizeof(buffer));
nret = send(theSocket, buffer, sizeof(buffer),0);
if (nret == SOCKET_ERROR)
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client send()");
closesocket(theSocket);
WSACleanup();
}
do
{
char buff[256];
nret = recv(theSocket, buff, sizeof(buff), 0);
if (nret > 0)
{
memcpy(keys, buff, sizeof(keys));
}
else if (nret == 0)
cout << "Server connection closed" << endl;
else
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client receive()");
closesocket(theSocket);
WSACleanup();
}
} while (nret > 0);
正如我所说,客户端和服务器之间正在建立连接,但该过程的接收部分似乎不起作用。任何帮助将不胜感激。
NetworkClient的启动方法:
sockVersion = MAKEWORD(1, 1);
// Initialize Winsock as before
WSAStartup(sockVersion, &wsaData);
// Store information about the server
LPHOSTENT hostEntry;
hostEntry = gethostbyname(serverAddress); // Specifying the server by its name;
if (!hostEntry) {
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client gethostbyname()"); // Report the error as before
closesocket(theSocket);
WSACleanup();
}
// Create the socket
theSocket = socket(AF_INET, // Go over TCP/IP
SOCK_STREAM, // This is a stream-oriented socket
IPPROTO_TCP); // Use TCP rather than UDP
if (theSocket == INVALID_SOCKET) {
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client socket()");
closesocket(theSocket);
WSACleanup();
}
// Fill a SOCKADDR_IN struct with address information
serverInfo.sin_family = AF_INET;
serverInfo.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list);
serverInfo.sin_port = htons(PORT); // Change to network-byte order and
// insert into port field
// Connect to the server
nret = connect(theSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr));
if (nret == SOCKET_ERROR)
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client connect()");
closesocket(theSocket);
WSACleanup();
}
// Successfully connected!
started = true;
Now I'm new to the WINSOCKs, and not super fluent in C++, so bear with me. I've written a NetworkServer and NetworkClient class, mostly based off of the MSDN tutorials. The client will be sending the server a char array of size 256, containing the state of each standard keyboard button (0 means the key is not being pressed, 1 means it is being pressed).
When running the code, I first start the server, and then the client. They connect to each other fine. The client is then called to send the keyboard buffer. The buffer is sent, but the server hangs after:
receiveResult = recv(theClient, buffer, sizeof(buffer), 0);
The "keys" variable in each class is a char keys[256] to hold each of the key states.
Below is the loop that occurs once a NetworkServer has been started:
char buffer[256];
int receiveResult, sendResult;
// Receive from the client
do
{
receiveResult = recv(theClient, buffer, sizeof(buffer), 0);
if (receiveResult > 0 )
{
sendResult = send(theClient, buffer, receiveResult, 0);
if (sendResult == SOCKET_ERROR)
{
sendResult = WSAGetLastError();
JBS::reportSocketError(nret, "server send()");
closesocket(theClient);
WSACleanup();
return;
}
else
{
memcpy(keys, buffer, sizeof(keys));
}
}
else if (receiveResult == 0)
cout << "Server closing." << endl;
else
{
receiveResult = WSAGetLastError();
JBS::reportSocketError(nret, "server receive()");
closesocket(theClient);
WSACleanup();
return;
}
} while (receiveResult > 0);
And here is the NetworkClient send method:
char buffer[256];
memcpy(buffer, keys, sizeof(buffer));
nret = send(theSocket, buffer, sizeof(buffer),0);
if (nret == SOCKET_ERROR)
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client send()");
closesocket(theSocket);
WSACleanup();
}
do
{
char buff[256];
nret = recv(theSocket, buff, sizeof(buff), 0);
if (nret > 0)
{
memcpy(keys, buff, sizeof(keys));
}
else if (nret == 0)
cout << "Server connection closed" << endl;
else
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client receive()");
closesocket(theSocket);
WSACleanup();
}
} while (nret > 0);
As I said, the connection is being established between client and server, but the receiving part of the process doesn't seem to be working. Any help would be appreciated.
NetworkClient's start method:
sockVersion = MAKEWORD(1, 1);
// Initialize Winsock as before
WSAStartup(sockVersion, &wsaData);
// Store information about the server
LPHOSTENT hostEntry;
hostEntry = gethostbyname(serverAddress); // Specifying the server by its name;
if (!hostEntry) {
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client gethostbyname()"); // Report the error as before
closesocket(theSocket);
WSACleanup();
}
// Create the socket
theSocket = socket(AF_INET, // Go over TCP/IP
SOCK_STREAM, // This is a stream-oriented socket
IPPROTO_TCP); // Use TCP rather than UDP
if (theSocket == INVALID_SOCKET) {
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client socket()");
closesocket(theSocket);
WSACleanup();
}
// Fill a SOCKADDR_IN struct with address information
serverInfo.sin_family = AF_INET;
serverInfo.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list);
serverInfo.sin_port = htons(PORT); // Change to network-byte order and
// insert into port field
// Connect to the server
nret = connect(theSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr));
if (nret == SOCKET_ERROR)
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client connect()");
closesocket(theSocket);
WSACleanup();
}
// Successfully connected!
started = true;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在客户端代码中,您写道:
这意味着您希望将数据接收到长度为
strlen(buff)
的缓冲区中。不幸的是,strlen() 返回缓冲区内字符串的长度,即缓冲区内任何 NUL 字符之前的数据长度。您的编译器足够聪明,可以使用 NUL 字符初始化buff
,因此strlen(buf)
返回 0,这意味着您希望接收 0 字节的数据。因此,recv()
没有收到任何内容。你的意思是:
(如果你尝试使用Release版本编译你的程序,它会很高兴地崩溃,因为
buff
将不会被初始化,并且strlen() 会返回一个相当随机的结果,这会导致程序访问无效的内存地址...)
我应该补充一点,你声明缓冲区的方式是不幸的:你有一个布尔数组(值1 或 0 取决于按键的状态)。布尔值不是字符。严格的声明应该是
bool buff[256]
...in the client code, you wrote:
this means that you want to receive data into a buffer which length is
strlen(buff)
. unfortunately,strlen()
returns the length of the string inside the buffer, that is the length of data before any NUL character inside the buffer. your compiler was smart enough to initializebuff
with NUL characters, thusstrlen(buf)
returns 0, which means that you want to receive 0 bytes of data. thus,recv()
does not receive anything.what you meant is:
(if you tried compiling your program using the Release build, it would have crashed happily, because
buff
would then not be initialized, andstrlen()
would have returned a pretty random result which would have caused the program to access an invalid memory address...)i should add that the way you declare your buffer is unfortunate: you have an array of booleans (value 1 or 0 depending of the state of keys). a boolean is not a char. a strict declaration should be
bool buff[256]
...问题最终是我如何在 keyBuffer 中分配值。我正在做
而不是
Problem ended up being how I was assigning the values in the keyBuffer. I was doing
Instead of