Sign in to follow this  

problem using threads with winsock2

This topic is 3632 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I don't know if it is against the forum's rules, i kind have maked a similar thread already, but it is a realy annoying problem, and i can't solve it by myself. So... I am working on a Class to encapsulate the winsock2 API, I'm trying to create a class similar to MFC's CAsyncSocket class, but using threads instead of windows messages. The entire Class(some variables and comments are in portuguese)
#include <iostream>
#include "circ.h"//include all others .h files



CSocket::CSocket()
{
    lasterror=0;
    host2=NULL;
    FD_ZERO(&set);
    time.tv_sec=0;
    time.tv_usec=0;

}
CSocket::~CSocket()
{
    //dtor
}
int CSocket::Create()
{
    //CRIA UM CLIENT

    //inicializa a utilização de sockets (versão 2,2)
    WSADATA w;
    int error = WSAStartup (MAKEWORD(2,2), &w);
    if (error!=0) //se houver erro
    {
        lasterror= WSAGetLastError();
        return error;
    }


    s=socket(AF_INET,SOCK_STREAM,0); //cria um socket sem porta  tcp/ip

    if (s==INVALID_SOCKET) //se s é um socket invalido
    {
        lasterror= WSAGetLastError(); //captura o erro
        WSACleanup ();
        return SOCKET_ERROR;
    }
    FD_SET(s,&set);
    return 0;

}
int CSocket::Create(unsigned int porta)
{

    //CRIA UM SERVER


    WSADATA w;
    int error1 = WSAStartup (MAKEWORD(2,2), &w); //inicializa a utilização de sockets(verção 2,2)
    if (error1!=0)
    {
        lasterror= WSAGetLastError();
        return error1; //se der erro, retorna o erro
    }

    s=socket(AF_INET,SOCK_STREAM,0); //cria um socket sem porta  tcp/ip
    if (s==INVALID_SOCKET)
    {
        lasterror=WSAGetLastError();
        WSACleanup ();
        return SOCKET_ERROR;
    }

    int error2;
    sockaddr_in addr;//estrutura que guarda os endereços tcp/ip

    addr.sin_family=AF_INET; // familia da internet
    addr.sin_port=porta; // Designa a porta
    addr.sin_addr.s_addr=INADDR_ANY; //endereço X desnecesário no momento

    error2=bind(s,(LPSOCKADDR)&addr,sizeof(addr));//Criando o server
    if (error2==SOCKET_ERROR)
    {
        lasterror = WSAGetLastError(); //captura o erro
        WSACleanup ();
        return error2; //retorna o erro
    }

    FD_SET(s,&set);
    return 0;
}

int CSocket::Connect(char* host, unsigned int porta)
{
    //COnecta tanto ip quanto hostname

    HOSTENT *hostinfo; //estrutura que guarda informações do host
    host2=host;
    hostinfo = gethostbyname(host);

    if (hostinfo==NULL)
    {
        lasterror= WSAGetLastError(); //captura o erro
        return HOSTNAMEERROR; // retorna erro do host
    }

    SOCKADDR_IN target; //estrutura que vai guradar as informações para conexão, ip...

    target.sin_family=AF_INET; //família da internet
    target.sin_port=htons(porta); //atribuindo uma porta para conexão

    target.sin_addr.S_un.S_un_b.s_b1=(unsigned char)hostinfo->h_addr_list[0][0]; // prenchendo o ip
    target.sin_addr.S_un.S_un_b.s_b2=(unsigned char)hostinfo->h_addr_list[0][1];
    target.sin_addr.S_un.S_un_b.s_b3=(unsigned char)hostinfo->h_addr_list[0][2];
    target.sin_addr.S_un.S_un_b.s_b4=(unsigned char)hostinfo->h_addr_list[0][3];


    if (connect(s,(SOCKADDR*)(&target),sizeof(target))==SOCKET_ERROR)
    {

        lasterror= WSAGetLastError();//caprutura o erro
        return SOCKET_ERROR;//returna erro
    }

    OnConnect(); //chama o evento ao se conectar
    return 0; //returna tudo OK

}
int CSocket::Send(const char*buf, int size)
{

    //Envia

    if (send (s, buf, size,0)==SOCKET_ERROR)
    {
        lasterror=WSAGetLastError();//captura o erro
        return SOCKET_ERROR; //retorna erro
    }
    return 0; //retorna tudo OK

}



int CSocket::Listen(CSocket* Socket,int maxconn )
{
    if (listen(Socket->s,maxconn)==SOCKET_ERROR)
    {
        lasterror=WSAGetLastError();
        return SOCKET_ERROR;
    }
    return 0;
}

int CSocket::Receive(char* buf, int size)
{
    //inconlopeta

    if (recv (s, buf, size, 0)==SOCKET_ERROR)
    {
        lasterror=WSAGetLastError();
        return SOCKET_ERROR;
    }
    return 0;
}

void CSocket::OnConnect()
{
    _beginthread(loop,0,(PVOID)this);
   
}
void CSocket::OnReceive()
{
    char buffer[512];
    Receive(buffer,sizeof(buffer));
    std::cout<<buffer<<std::endl;
}

void CSocket::OnSend()
{
}

void CSocket::OnClose()
{
}
int CSocket::GetLastError()
{
    return lasterror;
}

char * CSocket::GetHost()
{
    return host2;
}

void CSocket::loop(void* parameter)
{


    CSocket *obj=reinterpret_cast<CSocket*>(parameter);
    int teste2;
    while(1==1)
    {
        teste2=select(0,&(obj->set),NULL,NULL,&(obj->time));
        if (teste2==SOCKET_ERROR)
        {
            obj->lasterror=WSAGetLastError();
            std::cout<<teste2<<std::endl;
            std::cout<<obj->lasterror<<std::endl;



        }
        else
        {
            std::cout<<teste2<<std::endl;
            obj->OnReceive();

        }
    }


}

When i test it with this line teste2=select(0,&(obj->set),NULL,NULL,&(obj->time));checking for readability, it dont work and returns... "WSAEINVAL 10022 Invalid argument. Some invalid argument was supplied (for example, specifying an invalid level to the setsockopt function). In some instances, it also refers to the current state of the socket—for instance, calling accept on a socket that is not listening." from msdn. but when a use this line instead, select(0,NULL,&(obj->set),NULL,&(obj->time)); checking for writability, select returns 1, like it should. So, i assume that my parameters passed to select are not the problem, but something else is wrong, something i can't figure out. i know there is something to be read becouse when i just read without use select i've receive the irc serve info. someone please, give me a hand.

Share this post


Link to post
Share on other sites
Quote:
I'm trying to create a class similar to MFC's CAsyncSocket class


Why?


Anyway...

The socket creation:
s=socket(AF_INET,SOCK_STREAM,0);
should be ... , IPPROTO_TCP);


The following
if (connect(s,(SOCKADDR*)(&target),sizeof(target))==SOCKET_ERROR)
should probably be
... == INVALID_SOCKET


You have also lots of confusion about who does what, with WSAStartup and socket creation over several methods, when they could all be in single constructor. But I don't know if this is the problem, since you don't show how you actually create the socket, so I can only assume you're doing it the right way.

Share this post


Link to post
Share on other sites
Well, I've tryed what you said and, as you predicted, it doesn't work. The funny thing is; in the first iteration of my infinit while loop, select returns 0, instead SOCKET_ERROR, but, after that, returns the old friends -1 10022.It must have something to do about the error. And happens just when asking for readability, every other select returns what it should.

Thanks anyway. Any other ideas?

Share this post


Link to post
Share on other sites
I very strongly suggest that you read the documentation for every function you are using carefully; there are a lot of minor problems with your code which, unfortunately, I don't really have time to get into at the moment.

For your immediate problem, see MSDN on select(), which indicates that the error code WSAEINVAL means that your timeout parameter is invalid for some reason. Try checking the timeout to make sure it is sane, or just pass a 0 timeout so the function returns immediately with the results (which is probably what you should do anyways).


As far as threading - I'm not sure from your code what you're expecting to happen here, or how you're determining that it doesn't do what you want. Do you have experience writing multithreaded code? Why did you choose to use threads for this instead of more typical approaches for writing sockets code? What specific issues, if any, did you encounter that made you want to write an asynchronous socket class?

(I ask because, typically, wanting such a class is a classic beginner mistake from someone who hasn't quite understood how sockets work. Don't worry, though; sockets are complicated and not really intuitive, so you're hardly alone.)


Just a few quick things - this is by no means everything that needs work in your code:

  • Every call to WSAStartup should have a matching call to WSACleanup, as noted in the documentation. Also, it's extremely rare that you need to call it more than once, so calling it just in main() or whatever should be fine.

  • Why have a destructor if it doesn't do anything? (Unless you're doing something with virtual inheritance which you didn't post, in which case you can ignore me [wink]

  • I'd recommend using RAII instead of having a separate Create function; in this case having the destructor close the socket is the logical arrangement. If you aren't familiar with C++'s RAII idiom, I highly recommend that you read up on it a bit.

  • Be aware that when you receive an incoming connection on a socket, the original listening socket isn't the same one that accepts the connection; see the documentation on listen and accept for details.


Lastly, there are some very good resources mentioned in the forum FAQ, which I highly recommend you check out for further reading.

Share this post


Link to post
Share on other sites
THANKS, THANKS, THANKS....

Now it's working fine. The problem was with the timeval{0,0}structure, when I replace it with a zero, everything gos OK. THANKS again!!!

Share this post


Link to post
Share on other sites
timeval{0,0} is a valid value. It means "test and immediately return." If you just pass 0 (NULL), it means "block until something interesting happens." Very different meanings. However, if you're inside a thread, then blocking might be just fine.

Share this post


Link to post
Share on other sites
Quote:
the timeval structure must be a const timeval


That has nothing to do with it. A timeval * will be converted to a timeval const * by the compiler.

It seems to me that your code previously didn't work the way you expected, and now it does. However, it also seems to me that you don't know why that's actually the case. That, in turn, indicates that you are probably in a little bit over your head, and probably should spend some time learning more about your tools (language/compiler/library) before you advance into concepts like multi-threaded distributed programming.

Share this post


Link to post
Share on other sites

This topic is 3632 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this