我正在制作简单的TCP多客户端游戏用于学习 我将服务器广播收到的数据发送给客户,客户发送数据。
问题是,当三台以上的客户端连接到服务器时,接收数据的订单不是顺序的
1.客户发送职位
2.server收到并向其他客户广播
3.客户根据收到的数据接收和绘制
订单被更改(我认为因为线程优先级没有排序)所以图纸显示闪烁的图像 这是我的服务器代码&客户代码......
#include <stdio.h>
#include <WinSock2.h>
#include<string>
#include "Packet.h"
#define MAX_CLIENT 8
SOCKET socketClient[MAX_CLIENT];
///////////////////////////////////////////////////
Packet recvPacket[MAX_CLIENT];
char receiveBuffer[MAX_CLIENT][PACKETBUFFERSIZE];
int receivedPacketSize[MAX_CLIENT] = { 0,0,0,0,0,0,0,0 };
///////////////////////////////////////////////////
//
DWORD WINAPI NetReceive(LPVOID socketClient_)
{
char tempBuffer[127];
Packet recvPacket;
char receiveBuffer[PACKETBUFFERSIZE];
char recvBuffer[PACKETBUFFERSIZE];
int recvBytes;
int bufSize;
int receivedPacketSize = 0;
bufSize = PACKETBUFFERSIZE - receivedPacketSize;
while (1) {
bool broad = true;
if ((recvBytes = recv((SOCKET)socketClient_, &(receiveBuffer[receivedPacketSize]), bufSize, 0)) < 1) {
// 통신이 끝난 후에는 클라이언트의 접속을 해제한다.
//printf("*** Closed the client : %d(%d)\n", (SOCKET)socketClient_);
::shutdown((SOCKET)socketClient_, SD_BOTH);
::closesocket((SOCKET)socketClient_);
socketClient_ = (LPVOID)INVALID_SOCKET;
break;
}
receivedPacketSize += recvBytes;
while (receivedPacketSize > 0) // parsing Packet Length
{
recvPacket.copyToBuffer(receiveBuffer, receivedPacketSize);
int packetlength = (int)recvPacket.getPacketSize();
if (receivedPacketSize >= packetlength)
{
for (int a = 0;a < MAX_CLIENT;a++) {
if ((SOCKET)socketClient_ != INVALID_SOCKET) {
if ((SOCKET)socketClient_ == socketClient[a]) {
if (recvPacket.getPacketBuffer()[4] == 9 + '0') {
recvPacket.getPacketBuffer()[4] = a + '0';
broad = false;
}
}
}
}
// Parsing, main routine
recvPacket.readData(recvBuffer, recvPacket.getDataFieldSize());
//printf("(%d Bytes, ID=%d) %s\n", recvPacket.getDataFieldSize(), recvPacket.id(), recvBuffer);
//::send( socketClient[k], recvBuffer, strlen(recvBuffer)+1, 0 );
for (int a = 0;a < MAX_CLIENT;a++) {
if ((SOCKET)socketClient[a] != INVALID_SOCKET) {
if (broad == true) {
if ((SOCKET)socketClient_ != socketClient[a])
::send((SOCKET)socketClient[a], recvPacket.getPacketBuffer(), recvPacket.getPacketSize(), 0);
printf("(%d Bytes, ID=%d,broad) %s\n", recvPacket.getDataFieldSize(), recvPacket.id(), recvBuffer);
}
if (broad == false) {
if ((SOCKET)socketClient_ == socketClient[a])
::send((SOCKET)socketClient[a], recvPacket.getPacketBuffer(), recvPacket.getPacketSize(), 0);
printf("(%d Bytes, ID=%d,echo) %s\n", recvPacket.getDataFieldSize(), recvPacket.id(), recvBuffer);
}
}
}
receivedPacketSize -= packetlength;
if (receivedPacketSize > 0)
{
::CopyMemory(recvBuffer, (receiveBuffer + recvPacket.getPacketSize()), receivedPacketSize);\
::CopyMemory(receiveBuffer, recvBuffer, receivedPacketSize);
//printf("%s", recvBuffer);
}
}
else
break;
}
}
return NULL;
}
//
void main()
{
HANDLE handleThread[MAX_CLIENT];
WSADATA wsaData;
SOCKET socketListen, socketTemp;
// kimty
struct sockaddr_in serverAddr;
int k;
// 네트워크를 초기화 한다.
::WSAStartup(0x202, &wsaData);
for (k = 0;k < MAX_CLIENT;k++) // kimty
socketClient[k] = INVALID_SOCKET;
socketListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketListen == INVALID_SOCKET)
{
printf("Socket create error !!\n");
return;
}
::memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = ::htonl(INADDR_ANY); // ::inet_addr( "165.194.115.25" ); //::htonl( INADDR_LOOPBACK INADDR_ANY );
serverAddr.sin_port = ::htons(8600);
if (::bind(socketListen, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
printf("bind failed!! : %d\n", ::WSAGetLastError());
return;
}
if (::listen(socketListen, SOMAXCONN) == SOCKET_ERROR)
{
printf("listen failed!! : %d\n", ::WSAGetLastError());
return;
}
printf("****** Server Start with Maximum %d at %s ***\n", MAX_CLIENT, ::inet_ntoa(serverAddr.sin_addr));
//////////////////////////////////////////////////////////////////// server loop
while (1)
{
fd_set fds;
struct timeval tv = { 0, 100 }; // 0.1 초
FD_ZERO(&fds);
FD_SET(socketListen, &fds);
for (k = 0;k < MAX_CLIENT;k++)
if (socketClient[k] != INVALID_SOCKET)
FD_SET(socketClient[k], &fds);
::select(MAX_CLIENT + 2, &fds, 0, 0, &tv); // zero ?
if (FD_ISSET(socketListen, &fds))
{
struct sockaddr_in fromAddr;
int size = sizeof(fromAddr);
for (k = 0;k < MAX_CLIENT;k++)
if (socketClient[k] == INVALID_SOCKET)
break;
if (k == MAX_CLIENT) {
printf("*** Maximum client: Unable to accept ! %d\n", MAX_CLIENT);
socketTemp = ::accept(socketListen, (struct sockaddr*)&fromAddr, &size);
::shutdown(socketTemp, SD_BOTH);
::closesocket(socketTemp);
socketTemp = INVALID_SOCKET;
}
else
{
socketClient[k] = ::accept(socketListen, (struct sockaddr*)&fromAddr, &size);
if (socketClient[k] != SOCKET_ERROR)
printf("*** Accepted a client : %d(%d) from %s\n", k, socketClient[k], ::inet_ntoa(fromAddr.sin_addr));
}
}
else
{
for (k = 0;k < MAX_CLIENT;k++)
if (socketClient[k] != INVALID_SOCKET && FD_ISSET(socketClient[k], &fds))
{
handleThread[k] = CreateThread(NULL, 0, NetReceive, (void *)socketClient[k], 1, NULL);
}
}
}
//////////////////////////////////////////////////////////////////// end of server
::WSACleanup();
}
#include <stdio.h>
#include <WinSock2.h>
#include <ws2tcpip.h>
#include "wtpipv6.h"
#include "wspiapi.h"
#include "Packet.h"
//**********************************************************************
void usage(char *progname)
{
fprintf(stderr, "usage: %s [-n name] [-p port] \n", progname);
fprintf(stderr, " -n name Host name to resolve, [127.0.0.1] \n");
fprintf(stderr, " -p port Port number to resolve, [8600] \n");
ExitProcess(-1);
}
int resolveAddr(int argc, char **argv, char *serverName, char *serverPort)
{
int count, rc, i;
serverName[0] = 0;
serverPort[0] = 0;
for (i = 1; i < argc;i++)
{
if ((argv[i][0] != '-') && (argv[i][0] != '/') && (strlen(argv[i]) < 2))
usage(argv[0]);
switch (tolower(argv[i][1]))
{
case 'n': // name to resolve
if (i + 1 >= argc)
usage(argv[0]);
strcpy(serverName, argv[++i]);
break;
case 'p': // port/service to resolve
if (i + 1 >= argc)
usage(argv[0]);
strcpy(serverPort, argv[++i]);
break;
default:
usage(argv[0]);
break;
}
}
if (serverName[0] == 0)
strcpy(serverName, "127.0.0.1");
if (serverPort[0] == 0)
strcpy(serverPort, "8600");
//printf("** Resolve Address %s:%s \n", serverName, serverPort);
//******************* remoteHost = gethostbyname(host_name);
struct hostent *remoteHost;
remoteHost = gethostbyname(serverName); // ns.cau.ac.kr
//printf(">> gethostbyname Official name: %s", remoteHost->h_name);
struct in_addr addr;
addr.s_addr = *(u_long *)remoteHost->h_addr_list[0];
printf("-(%s) \n", inet_ntoa(addr));
if (!isalpha(serverName[0]))
{
struct in_addr addr = { 0 };
addr.s_addr = inet_addr(serverName); // 127.0.0.1
remoteHost = gethostbyaddr((char *)&addr, 4, AF_INET);
//printf(">> gethostbyaddr Official name: %s\n", remoteHost->h_name);
}
//*****************************************************************************
// Resolve the name/address - first assume that the name might be a string
// literal address
struct addrinfo hints, *res = NULL, *ptr;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
rc = getaddrinfo(serverName, serverPort, &hints, &res);
if (rc != 0)
{
if (rc == WSAHOST_NOT_FOUND)
{
hints.ai_flags = AI_CANONNAME;
printf("** AI_CANONNAME\n");
rc = getaddrinfo(serverName, serverPort, &hints, &res);
if (rc != 0)
{
fprintf(stderr, "getaddrinfo failed: %d\n", rc);
return -1;
}
}
else
{
fprintf(stderr, "getaddrinfo failed: %d\n", rc);
return -1;
}
}
// Count how many addresses were returned
count = 0;
ptr = res;
while (ptr)
{
count++;
ptr = ptr->ai_next;
}
// printf("** Hostname '%s' resolved to %d addresses\n", serverName, count);
//Do a reverse lookup on each of the resolved address
char numerichost[NI_MAXHOST];
rc = getnameinfo(res->ai_addr, res->ai_addrlen, numerichost, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); // NI_NAMEREQD, NI_NUMERICHOST
if (rc != 0)
{
fprintf(stderr, "getnameinfo failed: %d\n", rc);
return -1;
}
strcpy(serverName, numerichost);
printf(">> Numeric address resolved: %s:%s\n", serverName, serverPort);
// Free up the results from getaddrinfo
freeaddrinfo(res);
return 1;
}
//************************************************************************
void CommRecv(char *recvData);
DWORD WINAPI NetReceive(LPVOID socketConnect)
{
char recvBuffer[PACKETBUFFERSIZE] = { 0 };
int RecvBytes;
Packet recvPacket;
char receiveBuffer[PACKETBUFFERSIZE];
int receivedPacketSize = 0;
while (1) {
///////////////////////////////////////////////////////
int bufSize = PACKETBUFFERSIZE - receivedPacketSize;
if ((RecvBytes = recv((SOCKET)socketConnect, &(receiveBuffer[receivedPacketSize]), bufSize, 0))<1) {
::shutdown((SOCKET)socketConnect, SD_BOTH);
::closesocket((SOCKET)socketConnect);
socketConnect = (LPVOID)INVALID_SOCKET;
break;
}
receivedPacketSize += RecvBytes;
while (receivedPacketSize > 0) // parsing Packet Length
{
recvPacket.copyToBuffer(receiveBuffer, receivedPacketSize);
int packetlength = (int)recvPacket.getPacketSize();
if (receivedPacketSize >= packetlength)
{
// Parsing, main routine
recvPacket.readData(recvBuffer, recvPacket.getDataFieldSize());
printf("(%d Bytes, ID=%d) %s\n", recvPacket.getDataFieldSize(), recvPacket.id(), recvBuffer);
CommRecv(recvBuffer);
receivedPacketSize -= packetlength;
if (receivedPacketSize > 0)
{
::CopyMemory(recvBuffer, (receiveBuffer + recvPacket.getPacketSize()), receivedPacketSize);
::CopyMemory(receiveBuffer, recvBuffer, receivedPacketSize);
}
}
else {// if(recvPacket.id()==0){
printf("(%d Bytes, ID=%d) %s\n", recvPacket.getDataFieldSize(), recvPacket.id(), receiveBuffer);
// receivedPacketSize=0;
break;
}
}
///////////////////////////////////////////////////////
}
return NULL;
}
SOCKET socketConnect = INVALID_SOCKET;
void CommInit(int argc, char **argv)
{
WSADATA wsaData;
struct sockaddr_in serverAddr;
HANDLE handleThread;
::WSAStartup(0x202, &wsaData);
socketConnect = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketConnect == INVALID_SOCKET)
{
printf("Cannot create socket !!\n");
}
//******************************* Address and port resolve
char serverName[120], serverPort[120];
if (resolveAddr(argc, argv, serverName, serverPort)<1) {
printf("*** Unable to resolve server name !\n");
ExitProcess(-1);
}
// 접속할 서버의 정보를 설정한다.
::memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = ::inet_addr(serverName);
serverAddr.sin_port = ::htons(atoi(serverPort));
//********************************************************
if (socketConnect != INVALID_SOCKET) {
if (::connect(socketConnect, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
// printf( "Cannot connect to server !!\n");
socketConnect = INVALID_SOCKET;
ExitProcess(-1);
}
else {
// create thread for receive
handleThread = CreateThread(NULL, 0, NetReceive, (void *)socketConnect, THREAD_PRIORITY_NORMAL, NULL);
}
}
}
void CommSend(char *sending)
{
char sendData[50];
Packet sendPacket;
int sentBytes;
if (socketConnect == INVALID_SOCKET)
return;
sprintf(sendData, "%s", sending);
sendPacket.clear();
sendPacket.id(1001);
sendPacket.writeData(sendData, strlen(sendData) + 1);
sentBytes = ::send(socketConnect, sendPacket.getPacketBuffer(), sendPacket.getPacketSize(), 0);
if (sentBytes<0) {
::shutdown(socketConnect, SD_BOTH);
::closesocket(socketConnect);
socketConnect = INVALID_SOCKET;
}
}
extern void _GameProc(char *recvData);
void CommRecv(char *recvData)
{
_GameProc(recvData);
}