TCP / IP如何顺序发送& recv?

时间:2018-06-10 09:15:45

标签: c networking tcp

我正在制作简单的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);

}

0 个答案:

没有答案