![]() |
| | #1 |
| carry on Join Date: Feb 2003 Location: Seattle, WA
Posts: 1,971
| I can tell something is working, because I receive a FD_ACCEPT message on the instance I set to listen, but then my program never seems to reach any code after I call accept(): My window proc: Code: LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
CreateWindowEx(0, //more or 'extended' styles
TEXT("BUTTON"), //'class' of control to create
TEXT("Connect"), //the control caption
WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON, //control style: how it looks
10, //control position: left
10, //control position: top
100, //control width
20, //control height
hwnd, //parent window handle
(HMENU)IDC_CONNECT, //control's ID
g_hInst, //application instance
NULL);
CreateWindowEx(0, //more or 'extended' styles
TEXT("BUTTON"), //'class' of control to create
TEXT("Wait"), //the control caption
WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON, //control style: how it looks
120, //control position: left
10, //control position: top
100, //control width
20, //control height
hwnd, //parent window handle
(HMENU)IDC_SERVER, //control's ID
g_hInst, //application instance
NULL);
break;
case WM_WSAASYNC:
// what word?
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
MessageBox(NULL,"Connection request received","Alert!",MB_OK); //this comes up
// check for an error
if (WSAGETSELECTERROR(lParam))
return(FALSE);
// process message
try
{
netwkobj.Accept();
}
catch (const NetErr& error)
{
MessageBox(NULL,error.what(),"Network Error",MB_OK|MB_ICONEXCLAMATION);
}
return(0);
break;
case FD_READ:
//receiving data
break;
case FD_WRITE:
//..
break;
case FD_CONNECT:
//server got our connect message
MessageBox(NULL,"Connect request accepted","Alert!",MB_OK); // this never comes up
break;
case FD_CLOSE:
//connection closed
PostQuitMessage(0); //just quit for now...i guess
break;
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_CONNECT: //button pressed: try to connect to a server
try
{
netwkobj.Init(hwnd,false);
netwkobj.Connect("192.168.2.15");
}
catch (const NetErr& error)
{
MessageBox(NULL,error.what(),"Network Error!",MB_OK|MB_ICONEXCLAMATION);
}
//MessageBox(NULL,"Connected","OK",MB_OK);
break;
case IDC_SERVER:
try
{
netwkobj.Init(hwnd,true); //move this to when we try to join or host a game in a menu
}
catch (const NetErr& error)
{
MessageBox(NULL,error.what(),"Network Error!",MB_OK|MB_ICONEXCLAMATION);
}
// MessageBox(NULL,"Listening...","OK",MB_OK);
break;
}
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
Code: //network class member fcns
Network::Network()
{
hSocket = INVALID_SOCKET;
numclients=0;
}
void Network::Init(HWND hwnd, bool isserver)
{
init = true;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(REQ_WINSOCK_VER,0), &wsaData)==0) //start winsock
{
// Check if major version is at least REQ_WINSOCK_VER
if (LOBYTE(wsaData.wVersion) < REQ_WINSOCK_VER)
{
throw NetErr("Required Winsock Version not met!");
}
}
else
throw NetErr("Error starting Winsock!");
// create and test the socket
hSocket = socket(AF_INET, SOCK_STREAM, 0);
if (hSocket == INVALID_SOCKET)
throw NetErr("INVALID_SOCKET");
// make the socket asynchronous and notify of read, write, connect and close events
// this is the client socket
if (!isserver)
{
WSAAsyncSelect(hSocket, hwnd, WM_WSAASYNC, FD_WRITE | FD_CONNECT |
FD_READ | FD_CLOSE); //set up asynchronous sockets
//request WRITE, READ, CONNECT, and CLOSE messages be sent
server=false;
}
// make the socket asynchronous and notify of read, write, accept and close events
// this is the server socket
else
{
//is this the right order? (set to listen before call to WSAAsyncSelect()?
sockaddr_in sockAddr = {0};
SetServerSockAddr(&sockAddr, SERVER_PORT);
if (bind(hSocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr))!=0)
throw NetErr("Could not bind socket.");
if (listen(hSocket, SOMAXCONN)!=0) //set socket to listen for incoming data
throw NetErr("Could not put socket into listening mode.");
WSAAsyncSelect(hSocket, hwnd, WM_WSAASYNC, FD_READ | FD_WRITE |
FD_ACCEPT | FD_CLOSE); //again, async sockets
server=true;
}
}
void Network::Connect(const char* servIp)
{
if (!init)
throw NetErr("Network not initialized!");
sockaddr_in sockAddr = {0};
FillSockAddrDot(&sockAddr, servIp, SERVER_PORT);
if ((hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
throw NetErr("Could not create socket.");
// Connect to server
if (connect(hSocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr))!=0)
throw NetErr("Could not connect.");
}
void Network::Accept()
{
if (!init)
throw NetErr("Network not initialized!");
int clientSockSize = sizeof(client_addr);
client_sock[0] = accept(hSocket,reinterpret_cast<sockaddr*>(&client_addr), &clientSockSize);
//I never get an exception thrown, and if I put a messagebox here
//it never comes up
if (client_sock[numclients]==INVALID_SOCKET)
throw NetErr("Could not accept incoming connection");
numclients++;
}
Hopefully I'm just doing something stupid, since this is my first try with asynchronous sockets. Edit: Boy, I feel stupid. I guess WSAGETSELECTERROR is telling me there's an error. Somehow I just glanced over that line. Should've put some kind of notification there. Now I just gotta figure out what the error means... Edit2: MSDN doesn't have any error codes listed for the FD_ACCEPT message, and it returns error code 8...If I just continue like there's no problem, accept finished like there isn't a problem, but my client doesn't receive an FD_CONNECT message. Edit3: Yes, another edit. Ok so now I realize that there aren't actually any error (stupid tutorial told me wrong) But I still don't receive a FD_CONNECT message...I think I'll take a break on this now...
__________________ "Think not but that I know these things; or think I know them not: not therefore am I short Of knowing what I ought." -John Milton, Paradise Regained (1671) "Work hard and it might happen." -XSquared Last edited by JaWiB; 01-27-2005 at 10:07 PM. |
| JaWiB is offline | |
| | #2 |
| Yes, my avatar is stolen Join Date: Dec 2002
Posts: 2,544
| You'll probably spot this when you look at the code again but... 1. You are sharing the one netwkobj (and by extension the one socket variable) for both your client and server. This means that when you initiate the client you leak the server socket handle and replace it with the client socket handle. So when FD_ACCEPT arrives you are calling accept on the client socket handle. 2. Only call WSAStartup once at program startup. |
| anonytmouse is offline | |
| | #3 |
| carry on Join Date: Feb 2003 Location: Seattle, WA
Posts: 1,971
| I'm not sure I follow...I opened two instances of the application and click "wait" on one and "connect" on the other, so each open app should have it's own netwkobj, right? I also realize that if I press wait or connect twice, it won't work correctly, but I just don't do that (I'll probably fix that later)Maybe I just didn't explain myself well, or maybe I don't quite understand what you're saying
__________________ "Think not but that I know these things; or think I know them not: not therefore am I short Of knowing what I ought." -John Milton, Paradise Regained (1671) "Work hard and it might happen." -XSquared |
| JaWiB is offline | |
| | #4 |
| Yes, my avatar is stolen Join Date: Dec 2002
Posts: 2,544
| Yes, I thought this was all in the one instance. However, there is a similar problem. In the Network::Connect function you are creating a new socket and leaking the old one. This new socket is blocking and so the connect call will block. However, this doesn't explain why no conenction is established. Are you running any firewall software that may be blocking the accept call, for example waiting on user approval? |
| anonytmouse is offline | |
| | #5 | |
| carry on Join Date: Feb 2003 Location: Seattle, WA
Posts: 1,971
| Turns out that calling socket() twice and leaking my socket was the problem after all. Can't see how I missed that one. So now I get an FD_CONNECT message, but I can't seem to send or receive data. I went back to the tutorial I was reading and it says you need to fill the send buffer before it will actually send anything. So, I wanted to change the size of the buffer so that I don't have to send 8192 bytes or whatever it is. So I tried this: Code: void Network::Send(const char* data)
{
int bOptVal = strlen(data);
int bOptLen = sizeof(int);
setsockopt(hSocket,SOL_SOCKET, SO_SNDBUF, (char*)&bOptVal, bOptLen);
while(TRUE) {
if (send(hSocket, data, strlen(data), 0) == SOCKET_ERROR) { //send the whole read buffer
if (WSAGetLastError() != WSAEWOULDBLOCK) {
throw NetErr("Failed to send data.");
}
else {
return; //we have filled the buffer, we will wait for another FD_WRITE...
}
}
}
}
Quote:
And my message handler: Code: case FD_WRITE:
try
{
netwkobj.Send("Some data");
}
catch (const NetErr& error)
{
MessageBox(NULL,error.what(),"Error!",MB_OK);
}
MessageBox(NULL,"Data sent","Completed",MB_OK);
break;
case FD_READ:
{
//receiving data
char tempbuf[TEMP_BUFFER_SIZE];
int bytes_recv = recv(wParam, tempbuf, sizeof(tempbuf), 0);
MessageBox(NULL,tempbuf,"Received",MB_OK);
break;
}
Any more bright ideas?
__________________ "Think not but that I know these things; or think I know them not: not therefore am I short Of knowing what I ought." -John Milton, Paradise Regained (1671) "Work hard and it might happen." -XSquared Last edited by JaWiB; 01-28-2005 at 06:56 PM. | |
| JaWiB is offline | |
| | #6 |
| Yes, my avatar is stolen Join Date: Dec 2002
Posts: 2,544
| >> I went back to the tutorial I was reading and it says you need to fill the send buffer before it will actually send anything. << No, small packets will be sent. There may be a sub-second delay so any subsequent sends can be combined. See Nagle algorithm. You don't need to change the send buffer size unless you want to send larger amounts. I can't see any problems with your code except that you are not nul terminating the received data: Code: int bytes_recv = recv(wParam, tempbuf, sizeof(tempbuf) - 1, 0); if (bytes_recv >= 0) tempbuf[bytes_recv] = '\0'; MessageBox(NULL,tempbuf,"Received",MB_OK); |
| anonytmouse is offline | |
| | #7 |
| carry on Join Date: Feb 2003 Location: Seattle, WA
Posts: 1,971
| Ok so after doing some re-reading I guess I don't need to handle the FD_WRITE message at all (I can just send data when I need to), is that correct? And no I don't get any errors. As far as I can tell, the data is sent correctly, but I never get an FD_READ message (even if I put a messagebox before calling recv() it won't pop up)
__________________ "Think not but that I know these things; or think I know them not: not therefore am I short Of knowing what I ought." -John Milton, Paradise Regained (1671) "Work hard and it might happen." -XSquared |
| JaWiB is offline | |
| | #8 |
| Yes, my avatar is stolen Join Date: Dec 2002
Posts: 2,544
| >> Ok so after doing some re-reading I guess I don't need to handle the FD_WRITE message at all (I can just send data when I need to), is that correct? << No, you send until you receive a WSAEWOULDBLOCK and then you have to wait for a FD_WRITE before you can issue another send. Your sending seems find except you don't need to change the send buffer size. I don't know why it's not working. If you post something compilable, I can try it out. |
| anonytmouse is offline | |
| | #9 |
| carry on Join Date: Feb 2003 Location: Seattle, WA
Posts: 1,971
| For some reason on this computer I only receive the FD_WRITE message once when I connect, and then it doesn't come up again. But when I tried it on another computer I kept getting the FD_WRITE message, but still no FD_READ message. And if I need to fill up the buffer before I receive FD_WRITE again, can I still send small chunks of data, or is there another way of doing it? Anyways, I'll attach my code; hopefully my error is painfully obvious
__________________ "Think not but that I know these things; or think I know them not: not therefore am I short Of knowing what I ought." -John Milton, Paradise Regained (1671) "Work hard and it might happen." -XSquared |
| JaWiB is offline | |
| | #10 | |
| carry on Join Date: Feb 2003 Location: Seattle, WA
Posts: 1,971
| I think I might have figured it out. Here's what threw me (from msdn): Quote:
Code: void Network::Accept()
{
if (!init)
throw NetErr("Network not initialized!");
if (numclients>=MAX_CONNECTIONS)
throw NetErr("Too many connections"); //figure out how to handle this better later
int clientSockSize = sizeof(client_addr);
client_sock[numclients] = accept(hSocket,reinterpret_cast<sockaddr*>(&client_addr), &clientSockSize);
if (WSAAsyncSelect(client_sock[numclients], chwnd, WM_WSAASYNC, FD_CONNECT | FD_WRITE |
FD_READ | FD_CLOSE)!=0) //set up asynchronous sockets
//request WRITE, READ, CONNECT, and CLOSE messages be sent
{
throw NetErr("WSAAsyncSelect() Failed!");
}
if (client_sock[numclients]==INVALID_SOCKET)
throw NetErr("Could not accept incoming connection");
numclients++;
}
So I *think* everything works now, except I'm still not sure if I'll keep getting FD_WRITE messages if I'm only sending small pieces of data.
__________________ "Think not but that I know these things; or think I know them not: not therefore am I short Of knowing what I ought." -John Milton, Paradise Regained (1671) "Work hard and it might happen." -XSquared | |
| JaWiB is offline | |
| | #11 |
| Carnivore ('-'v) Join Date: May 2002
Posts: 2,866
| >>I only receive the FD_WRITE message once when I connect, and then it doesn't come up again. You get an FD_WRITE when you first connect, but after that you should never get another FD_WRITE until send() gives you a WSAEWOULDBLOCK. So you just keep sending and sending until WSAEWOULDBLOCK, and then you wait for FD_WRITE to let you know that it's safe to send again.
__________________ Just Google It. √ (\ /) ( . .) c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination. |
| Hunter2 is offline | |
| | #12 |
| carry on Join Date: Feb 2003 Location: Seattle, WA
Posts: 1,971
| Ok, so would it be safe to have my send function be like: Code: bool Network::Send(const char* data)
{
if (wait)
return false; //can't send data right now...
if (send(hSocket, data, strlen(data), 0) == SOCKET_ERROR) { //send the whole read buffer
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
throw NetErr("Failed to send data.");
}
wait=true;
}
return true;
}
__________________ "Think not but that I know these things; or think I know them not: not therefore am I short Of knowing what I ought." -John Milton, Paradise Regained (1671) "Work hard and it might happen." -XSquared |
| JaWiB is offline | |
| | #13 |
| Carnivore ('-'v) Join Date: May 2002
Posts: 2,866
| It looks about OK to me, except not all of the data might be transmitted in one send() - you might only get half of the data across, and the other half will be lost if you don't account for it somewhere. send() returns the number of bytes that were successfully transmitted, so you might want to have Send() return that instead of a bool. Something else fun to try would be to return false, but queue up the data in an internal buffer (or a list of buffers) and finish all incomplete sends the next time you call Send(), before beginning to send the new data - or perhaps even allow Send(NULL), which would mean that rather than sending any new data, Send() should just finish up sending any leftovers from a previous call
__________________ Just Google It. √ (\ /) ( . .) c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination. |
| Hunter2 is offline | |
| | #14 |
| carry on Join Date: Feb 2003 Location: Seattle, WA
Posts: 1,971
| Yeah, something like that sounds better. I could just add all the data that isn't sent to a buffer and then when FD_WRITE comes up again try to send it all again. But I think I might still want to return whether all the data is sent so I can display a message in the corner of the app or something (i.e. "Sending data...") And then I also have to make sure I receive everything on the other end. It keeps getting more and more complicated! Edit: And I also wonder if I need to have several buffers for the server app so it can store data for each client it needs to be sent to...
__________________ "Think not but that I know these things; or think I know them not: not therefore am I short Of knowing what I ought." -John Milton, Paradise Regained (1671) "Work hard and it might happen." -XSquared |
| JaWiB is offline | |
| | #15 |
| Carnivore ('-'v) Join Date: May 2002
Posts: 2,866
| >>It keeps getting more and more complicated! As you can probably tell from the other thread in Networking, I'm not having a ton of luck myself I had the whole 'unsent' buffer thing written out earlier and it even seemed to be working, but then everything else in my project broke and I couldn't figure it out, so I ended up scrapping the whole thing and starting over again. Hopefully Anonytmouse can get us all sorted out
__________________ Just Google It. √ (\ /) ( . .) c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination. |
| Hunter2 is offline | |
![]() |
| Thread Tools | |
| Display Modes | |
|
Similar Threads | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Cannot Accept Connections with Simple client/server program | NuNn | C Programming | 12 | 02-10-2009 02:14 PM |
| non-MFC DLL with MFC app question. | Kempelen | Windows Programming | 10 | 08-20-2008 07:11 AM |
| Bluetooth client/server app | wierdbeard65 | Networking/Device Communication | 0 | 06-12-2007 06:05 AM |
| best program to start | gooddevil | Networking/Device Communication | 4 | 05-28-2004 05:56 PM |
| pasword app | GanglyLamb | C Programming | 2 | 06-07-2003 10:28 AM |