Ir para conteúdo
Fórum Script Brasil
  • 0

(Resolvido) Server-Client Sockets


KaL

Pergunta

Boa noite, estou tentando estabelecer uma comunicação client-server em C++ para aprender a usar sockets (para uma aplicação futura a ser desenvolvida), estou usando a library da Microsoft (http://msdn.microsoft.com/en-us/library/sb27wehh.aspx) para começar, entretanto estou meio "empacado".

Como minha aplicação é um tanto quanto grande e será feita para múltiplas conexões, tentei fazer sem usar o TcpClient/Listener, pois no próprio artigo de sockets, eles são indicados apenas para aplicações pequenas.

Meu objetivo é criar uma comunicação SingleThreaded (vários sockets dentro de um Thread) non-blocking server. Anteriormente programei em java, então sei que é possível usar um sistema com threadpool para as sockets, possibilitando usar apenas uma thread.

Meu código para o server

#using <System.dll>

using namespace System;
using namespace System::Text;
using namespace System::IO;
using namespace System::Net;
using namespace System::Net::Sockets;
using namespace System::Collections;


Socket^ ConnectSocket( String^ server, int port )
{
    Socket^ s = nullptr;
    IPAddress^ address = IPAddress::Parse(server);
    IPEndPoint^ endPoint = gcnew IPEndPoint( address,port );
    s = gcnew Socket( endPoint->AddressFamily,SocketType::Stream,ProtocolType::Tcp );
    s->Bind(endPoint);
    s->Listen(1);

    array<Byte>^bytesReceived = gcnew array<Byte>(256);    
    String^ data = nullptr;    
    Int32 i;
    
    while ( true )
    {
        Console::Write( "Waiting for a connection... " );

        s->Accept();
        if(s->Connected)
            Console::WriteLine( "Connected!" );
        data = nullptr;

        // Loop to receive all the data sent by the client.
        while ( i = s->Receive( bytesReceived, bytesReceived->Length, static_cast<SocketFlags>(0)) )
        {
            // Translate data bytes to a ASCII String*.
            data = Text::Encoding::ASCII->GetString( bytesReceived, 0, i );
            if(data->Equals("exit") || data->Equals("Exit"))
            {
                s->Close();
                break;
            }
            Console::WriteLine( "Received: {0}", data );

            array<Byte>^msg = Text::Encoding::ASCII->GetBytes( "Connection received, type exit to disconnect." );

            // Send back a response.
            s->Send(msg,0, msg->Length, static_cast<SocketFlags>(0));
            continue;
        }
    }
}

int main()
{
    String^ host = "127.0.0.1";
    int port = 7777;

    ConnectSocket( host, port );
}
Para client
#using <System.dll>

using namespace System;
using namespace System::Text;
using namespace System::IO;
using namespace System::Net;
using namespace System::Net::Sockets;
using namespace System::Collections;
void ConnectSocket( String^ server, int port )
{
    Socket^ s = nullptr;
    IPAddress^ address = IPAddress::Parse(server);
    IPEndPoint^ endPoint = gcnew IPEndPoint( address,port );
    s = gcnew Socket( endPoint->AddressFamily,SocketType::Stream,ProtocolType::Tcp );
    s->Connect( endPoint );
    if(s->Connected)
        Console::WriteLine("Worked");

    array<Byte>^bytesSent = gcnew array<Byte>(256);
    array<Byte>^bytesReceived = gcnew array<Byte>(256);
    while(s != nullptr)
    {
        // Send request to the server.
        bytesSent = Text::Encoding::ASCII->GetBytes(Console::ReadLine());
        s->Send( bytesSent, bytesSent->Length, static_cast<SocketFlags>(0) );

        // Receive the server home page content.
        int bytes = 0;
        String^ data = nullptr;
        do
        {
            bytes = s->Receive( bytesReceived, bytesReceived->Length, static_cast<SocketFlags>(0) );
            data = String::Concat( data, Encoding::ASCII->GetString( bytesReceived, 0, bytes ) );
        }
        while ( bytes > 0 );
    }
}

int main()
{
    String^ host = "127.0.0.1";
    int port = 7777;

    ConnectSocket( host, port );
}

Obs.: Usei os métodos com block pois não consegui colocar os Async (não encontrei exemplos dos parâmetros das funções).

Tentei usar também os sockets com winsock (como este: http://scriptbrasil.com.br/forum/index.php?showtopic=152286), mas o Visual C++ dá um montão de erros no compilador: "error LNK2028: unresolved token (0A000028) "extern "C" char * __stdcall inet_ntoa(struct in_addr)" (?inet_ntoa@@$$J14YGPADUin_addr@@@Z) referenced in function "int __cdecl main(void)" (?main@@$$HYAHXZ)" (parcial do erro).

A parte do server funciona até eu ligar o client. Então o server trava e dá uma exceção na linha 28 (s->Accept()) alegando que não podem haver envios ou recebimentos pois não há conexão. Enquanto isso o client fica online normalmente (sem apresentar erros) e a o controlador da linha 16 (if(s->Connected) é executado, afirmando que há conexão.

Estou com Win 7 64 bits e Visual Studio 2010.

Alguém pode me dar uma mãozinha com isso? ;)

Se possível me mostrar algum caminho para montar a execução single-threaded non-blocking também!

Link para o comentário
Compartilhar em outros sites

4 respostass a esta questão

Posts Recomendados

  • 0

Obrigado! Consegui colocar os sockets para funcionar, mas surgiu uma dúvida enquanto eu tentava mudar o script.

A função bind do server apenas lê endereços internos? Quando eu coloco um IP WAN no getaddrinfo() ele dá erro no bind (nº 10049).

Como teria que fazer para poder colocar um endereço configurável?

Aqui o pedaço do código:

hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    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();
        return 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();
        return 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());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

Link para o comentário
Compartilhar em outros sites

Participe da discussão

Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.

Visitante
Responder esta pergunta...

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.



  • Estatísticas dos Fóruns

    • Tópicos
      152k
    • Posts
      651,8k
×
×
  • Criar Novo...