来自:http://www.codeproject.com/Articles/412511/Simple-client-server-network-using-Cplusplus-and-W
包含四个文件:
ServerNetwork.h //对服务端socket的初始化,数据收发
ServerNetwork.cpp
ServerGame.h //对数据收发的处理
ServerGame.cpp
#include <winsock2.h>
#include <ws2tcpip.h>
#include <map>
using namespace std;
#define DEFAULT_PORT "6881"
class ServerNetwork
{
public:
ServerNetwork(void);
~ServerNetwork(void);
// send data to all clients
void sendToAll(char * packets, int totalSize);
// receive incoming data
int receiveData(unsigned int client_id, char * recvbuf);
// accept new connections
bool acceptNewClient(unsigned int & id);
// Socket to listen for new connections
SOCKET ListenSocket;
// Socket to give to the clients
SOCKET ClientSocket;
// table to keep track of each client's socket
std::map<unsigned int, SOCKET> sessions;
};
#include "StdAfx.h"
#include "ServerNetwork.h"
#include "NetworkServices.h"
#include "NetworkData.h"
ServerNetwork::ServerNetwork(void)
{
int iResult;
// create WSADATA object
WSADATA wsaData;
// our sockets for the server
ListenSocket = INVALID_SOCKET;
ClientSocket = INVALID_SOCKET;
// address info for the server to listen to
struct addrinfo *result = NULL;
struct addrinfo hints;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
exit(1);
}
// set address information
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP; // TCP connection!!!
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
exit(1);
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
exit(1);
}
// Set the mode of the socket to be nonblocking
u_long iMode = 1;
iResult = ioctlsocket(ListenSocket, FIONBIO, &iMode);
if (iResult == SOCKET_ERROR) {
printf("ioctlsocket failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
exit(1);
}
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
exit(1);
}
// no longer need address information
freeaddrinfo(result);
// start listening for new clients attempting to connect
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
exit(1);
}
}
ServerNetwork::~ServerNetwork(void)
{
}
// accept new connections
bool ServerNetwork::acceptNewClient(unsigned int & id)
{
// if client waiting, accept the connection and save the socket
ClientSocket = accept(ListenSocket,NULL,NULL);
if (ClientSocket != INVALID_SOCKET)
{
//disable nagle on the client's socket
char value = 1;
setsockopt( ClientSocket, IPPROTO_TCP, TCP_NODELAY, &value, sizeof( value ) );
// insert new client into session id table
sessions.insert( pair<unsigned int, SOCKET>(id, ClientSocket) );
return true;
}
return false;
}
// receive incoming data
int ServerNetwork::receiveData(unsigned int client_id, char * recvbuf)
{
if( sessions.find(client_id) != sessions.end() )
{
SOCKET currentSocket = sessions[client_id];
int iResult;
iResult = NetworkServices::receiveMessage(currentSocket, recvbuf, MAX_PACKET_SIZE);
if (iResult == 0)
{
printf("Connection closed\n");
closesocket(currentSocket);
}
return iResult;
}
return 0;
}
// send data to all clients
void ServerNetwork::sendToAll(char * packets, int totalSize)
{
SOCKET currentSocket;
std::map<unsigned int, SOCKET>::const_iterator iter;
int iResult;
for (iter = sessions.begin(); iter != sessions.end(); ++iter)
{
currentSocket = iter->second;
iResult = NetworkServices::sendMessage(currentSocket, packets, totalSize);
if (iResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(currentSocket);
}
}
}
#include "ServerNetwork.h"
#include "NetworkData.h"
class ServerGame
{
public:
ServerGame(void);
~ServerGame(void);
void update();
private:
void receiveFromClients();
void sendActionPackets();
// IDs for the clients connecting for table in ServerNetwork
static unsigned int client_id;
// The ServerNetwork object
ServerNetwork* network;
// data buffer
char network_data[MAX_PACKET_SIZE];
};
#include "StdAfx.h"
#include "ServerGame.h"
//注:static 默认为0
unsigned int ServerGame::client_id;
ServerGame::ServerGame(void)
{
// id's to assign clients for our table
client_id = 0;
// set up the server network to listen
network = new ServerNetwork();
}
ServerGame::~ServerGame(void)
{
}
void ServerGame::update()
{
// get new clients
if(network->acceptNewClient(client_id))
{
printf("client %d has been connected to the server\n",client_id);
client_id++;
}
receiveFromClients();
}
void ServerGame::receiveFromClients()
{
Packet packet;
// go through all clients
std::map<unsigned int, SOCKET>::iterator iter;
for(iter = network->sessions.begin(); iter != network->sessions.end(); iter++)
{
int data_length = network->receiveData(iter->first, network_data);
if (data_length <= 0)
{
//no data recieved
continue;
}
unsigned int i = 0;
while (i < (unsigned int)data_length)
{
packet.deserialize(&(network_data[i]));
i += sizeof(Packet);
switch (packet.packet_type) {
case INIT_CONNECTION:
printf("server received init packet from client\n");
sendActionPackets();
break;
case ACTION_EVENT:
printf("server received action event packet from client\n");
sendActionPackets();
break;
default:
printf("error in packet types\n");
break;
}
}
}
}
void ServerGame::sendActionPackets()
{
// send action packet
const unsigned int packet_size = sizeof(Packet);
char packet_data[packet_size];
Packet packet;
packet.packet_type = ACTION_EVENT;
packet.serialize(packet_data);
network->sendToAll(packet_data,packet_size);
}
简单使用:
#include <process.h>
void serverLoop(void *);
ServerGame * server;
int main()
{
// initialize the server
server = new ServerGame();
// create thread with arbitrary argument for the run function
_beginthread( serverLoop, 0, (void*)12);
}
void serverLoop(void * arg)
{
while(true)
{
server->update();
}
}