gpt4 book ai didi

c++ - 我的 winsock 应用程序有问题

转载 作者:行者123 更新时间:2023-11-28 03:01:10 27 4
gpt4 key购买 nike

我的 Winsock 应用程序有一些问题。

就目前而言,当我的客户端首次连接到服务器时,欢迎消息发送正常,但就在那时它搞砸了。收到初始消息后,程序就进入了涡轮模式。

每个客户端都有一个存储需要发送的消息的 vector ,为了进行调试,我让它输出了还有多少消息要发送,这是最新消息的内容:

    Successfully sent message. 1 messages left.
Successfully sent message. 1574803 messages left
................... (Counts down)
Successfully sent message. 1574647 messages left
Client connection closed or broken

编辑:设法将一些输出代码放在正确的位置,出于某种原因,当它开始向客户端发送更新消息时,它开始一遍又一遍地发送相同的消息。

这里有一些代码,我只发布了 cpp,“Network::Update”由“Game”中的线程运行

-- 服务器 --

main.cpp

    while(true)
{
m_Game -> Update();
Sleep(500);
}

网络.cpp

    #include "Network.h"

Network::Network()
{
}

Network::~Network()
{
closesocket(m_Socket);
}

Network::Network(char* ServerIP, int ServerPort)
{
Initialise(ServerIP, ServerPort);
}

void Network::Initialise(char* ServerIP, int ServerPort)
{
//
// Initialise the winsock library to 2.2
//
WSADATA w;
int error = WSAStartup(0x0202, &w);
if ((error != 0) || (w.wVersion != 0x0202))
{
MessageBox(NULL, L"Winsock error. Shutting down.", L"Notification", MB_OK);
exit(1);
}

//
// Create the TCP socket
//
m_Socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_Socket == SOCKET_ERROR)
{
MessageBox(NULL, L"Failed to create socket.", L"Notification", MB_OK);
exit(1);
}

//
// Fill out the address structure
//
m_Address.sin_family = AF_INET;
m_Address.sin_addr.s_addr = inet_addr(ServerIP);
m_Address.sin_port = htons(ServerPort);

//
// Bind the server socket to that address.
//
if (bind(m_Socket, (const sockaddr *) &m_Address, sizeof(m_Address)) != 0)
{
MessageBox(NULL, L"Failed to bind the socket to the address.", L"Notification", MB_OK);
exit(1);
}

//
// Make the socket listen for connections.
//
if (listen(m_Socket, 1) != 0)
{
MessageBox(NULL, L"Failed to listen on the socket.", L"Notification", MB_OK);
exit(1);
}

m_ID = 1;
}

void Network::Update()
{
//
// Structures for the sockets
//
fd_set readable, writeable;
FD_ZERO(&readable);
FD_ZERO(&writeable);

//
// Let the socket accept connections
//
FD_SET(m_Socket, &readable);

//
// Cycle through clients allowing them to read and write
//
for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); ++it)
{
Client *client = *it;

if (client->wantRead())
{
FD_SET(client->sock(), &readable);
}

if (client->wantWrite())
{
FD_SET(client->sock(), &writeable);
}
}

//
// Structure defining the connection time out
//
timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 500000;

//
// Check if a socket is readable
//
int count = select(0, &readable, &writeable, NULL, &timeout);
if (count == SOCKET_ERROR)
{
ExitProgram(L"Unable to check if the socket can be read.\nREASON: Select failed");
}

//
// Check if a theres an incoming connection
//
if (FD_ISSET(m_Socket, &readable))
{
//
// Accept the incoming connection
//
sockaddr_in clientAddr;
int addrSize = sizeof(clientAddr);
SOCKET clientSocket = accept(m_Socket, (sockaddr *) &clientAddr, &addrSize);
if (clientSocket > 0)
{
// Create a new Client object, and add it to the collection.
Client *client = new Client(clientSocket);
m_Clients.push_back(client);

// Send the new client a welcome message.
NetworkMessage message;
message.m_Type = MT_Welcome;
client->sendMessage(message);

m_ID++;
}
}

//
// Loop through clients
//
for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); ) // note no ++it here
{
Client *client = *it;
bool dead = false;

//
// Read data
//
if (FD_ISSET(client->sock(), &readable))
{
dead = client->doRead();
}

//
// Write data
//
if (FD_ISSET(client->sock(), &writeable))
{
dead = client->doWrite();
}

//
// Check if the client is dead (Was unable to write/read packets)
//
if (dead)
{
delete client;
it = m_Clients.erase(it);
}
else
{
++it;
}
}
}

void Network::sendMessage(NetworkMessage message)
{
//Loop through clients and send them the message
for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); ) // note no ++it here
{
Client *client = *it;
client->sendMessage(message);
}
}

客户端.cpp

    #include "Client.h"

Client::Client(SOCKET sock)
{
m_Socket = sock;
send_count_ = 0;
}

// Destructor.
Client::~Client()
{
closesocket(m_Socket);
}

// Process an incoming message.
void Client::processMessage(NetworkMessage message)
{
// PROCESSING NEEDS TO GO HERE
}

// Return the client's socket.
SOCKET Client::sock()
{
return m_Socket;
}

// Return whether this connection is in a state where we want to try
// reading from the socket.
bool Client::wantRead()
{
// At present, we always do.
return true;
}

// Return whether this connection is in a state where we want to try-
// writing to the socket.
bool Client::wantWrite()
{
// Only if we've got data to send.
//return send_count_ > 0;

return Messages.size() > 0;
}

// Call this when the socket is ready to read.
// Returns true if the socket should be closed.
bool Client::doRead()
{
return false;
}

// Call this when the socket is ready to write.
// Returns true if the socket should be closed.
bool Client::doWrite()
{
/*int count = send(m_Socket, send_buf_, send_count_, 0);
if (count <= 0)
{
printf("Client connection closed or broken\n");
return true;
}

send_count_ -= count;

// Remove the sent data from the start of the buffer.
memmove(send_buf_, &send_buf_[count], send_count_);

return false;*/

int count = send(m_Socket, (char*)&Messages[0], sizeof(NetworkMessage), 0);
if( count <= 0 )
{
printf("Client connection closed or broken\n");
return true;
}
Messages.pop_back();
printf(" Successfully sent message. %d messages left.\n", Messages.size() );

return false;
}

void Client::sendMessage(NetworkMessage message)
{
/*if (send_count_ + sizeof(NetworkMessage) > sizeof(send_buf_))
{
ExitProgram(L"Unable to send message.\nREASON: send_buf_ full");
}
else
{
memcpy(&send_buf_[send_count_], message, sizeof(NetworkMessage));
send_count_ += sizeof(NetworkMessage);
printf(" Size of send_count_ : %d \n", send_count_);
}*/

Messages.push_back(message);
}

游戏.cpp

    void Game::Update()
{
tempPlayer -> ChangePosition(1, 1); //Increase X and Y pos by 1

Dispatch();
printf("Update\n");
}

void Game::Dispatch()
{
NetworkMessage temp;
temp.m_Type = MT_Update;
temp.m_ID = tempPlayer->getID();
temp.m_positionX = tempPlayer->getX();
temp.m_positionY = tempPlayer->getY();

m_Network->sendMessage(temp);
}

最佳答案

您的代码存在一些问题。

主要问题是 Network::sendMessage() 运行无限循环。你的 it 迭代器永远不会递增(有一条评论这么说 - 评论做错了!),所以循环将相同的 NetworkMessage 发送到相同的 Client 一遍又一遍,从未停止。改为这样做:

void Network::sendMessage(NetworkMessage message)
{
//Loop through clients and send them the message
for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); ++it)
{
...
}
}

Client::doWrite() 在应该使用 pop_front() 时使用了 pop_back()。如果 vector 中有多个未决消息,您将丢失消息。与其使用 [] 运算符将 NetworkMessage 直接传递给 send(),不如使用 pop_front()第一个未决消息,然后 send() 它:

bool Client::doWrite()
{
NetworkMessage message = Messages.pop_front();

int count = send(m_Socket, (char*)&message, sizeof(NetworkMessage), 0);
if( count <= 0 )
{
printf("Client connection closed or broken\n");
return true;
}

printf(" Successfully sent message. %d messages left.\n", Messages.size() );
return false;
}

你的 dead checkin Network::Update() 中有一个小的逻辑漏洞,如果 doRead() 返回 true,然后 doWrite() 返回 false。改为这样做:

bool dead = false;

//
// Read data
//
if (FD_ISSET(client->sock(), &readable))
{
if (client->doRead())
dead = true;
}

//
// Write data
//
if (FD_ISSET(client->sock(), &writeable))
{
if (client->doWrite())
dead = true;
}

关于c++ - 我的 winsock 应用程序有问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20820211/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com