我的Winsock应用程序遇到了一些问题。
目前看来,当我的客户端第一次连接到服务器时,欢迎消息被发送正常,但那就是搞砸了。在该初始消息之后,它就像程序进入turbo模式。
每个客户端都有一个存储需要发送的消息的向量,要调试我输出了剩余的消息要发送的内容以及最新消息的内容:
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);
}
Network.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);
}
}
Client.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);
}
Game.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);
}
答案 0 :(得分:2)
您的代码存在一些问题。
主要问题是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_back()
,而应使用pop_front()
。如果向量中有多个待处理消息,您将丢失消息。您应该[]
第一个待处理的消息,然后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
签入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;
}