Title: Problem with simple WinSock program
biggoron - January 21, 2007 03:18 PM (GMT)
Edit:
New problem: It compiles but just won't work. Now it appears that it's a question about a specific API so I guess it should be in the Miscellaneous Libraries section, but I'll leave it up to the forum staff.
The client program gets up to trying to bind but fails each time.
The server program works as it should so far. It gets up to listening and it waits.
I didn't really know where to put this, but it seems like a linker error to me so I didn't think it would be a question about a specific API so I put it here.
I'm trying to make a simple WinSock program that will make a server that the clients can connect to. The client compiles fine but the server won't.
| CODE |
#include <winsock2.h> #include <iostream>
#define MAX_CLIENTS 1
using namespace std;
void Error(char*);
int main(int argc, char *argv[]) { WSADATA wsaData; if(WSAStartup(0x0202, &wsaData)) { Error("Failure to initialise library"); return 1; } if(wsaData.wVersion != 0x0202) { Error("Wrong version used"); return 1; } cout << "Initialised\n"; SOCKET socListen = socket(AF_INET, SOCK_STREAM, 0); cout << "Socket made\n"; sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(5001); addr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(socListen, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) { Error("Failure to bind"); return 1; } cout << "Socket bound\n"; if(listen(socListen, MAX_CLIENTS) == SOCKET_ERROR) { Error("Failure to listen"); return 1; } cout << "Listening...\n"; int clients = 0; SOCKET client[MAX_CLIENTS]; sockaddr client_addr[MAX_CLIENTS];
while(clients < MAX_CLIENTS) { int size = sizeof(client_addr[clients]); client[clients] = accept(socListen, &client_addr[clients], &size); if(client[clients] == INVALID_SOCKET) { Error("Failure to receive connection"); return 1; } else { clients++; } } cout << "Client joined!\n"; Error("Success!"); return 0; }
void Error(char *str) { cout << str << "\n"; WSACleanup(); system("PAUSE"); } |
The error I get is:
| QUOTE |
| [Build error] ["WinSock] Error 1 |
I'm taking a wild guess but I think it might be a linker error. It doesn't seem to be a compile time error and it can't be a run time error so, yeah...
I've linked the ws2_32 library. I can't see the problem :(
Thanks.
Rmstn1580 - January 21, 2007 08:01 PM (GMT)
I compiled it and it ran fine for me. What compiler are you using? Also, could you send me the code for the client you made? :) I've been trying for weeks to get mine to work. I've been looking on forums, reading tutorials, etc. My program compiles but doesn't connect :(
biggoron - January 21, 2007 09:07 PM (GMT)
I'm using Dev-Cpp. If you used VC that might explain it. The tutorial I used was probably made for VC. All I did for my client app was basically copy fragments from the tutorial. Plus, it doesn't even work. It gets up to the binding then fails. Probably because I've set it to connect to my router's IP and I'm using it from within my PC though. Maybe something to do with port-forwarding... I dunno...
| CODE |
#include <winsock2.h> #include <iostream>
using namespace std;
void Error(char*);
int main(int argc, char *argv[]) { WSADATA wsaData; if(WSAStartup(0x0202, &wsaData)) { Error("Failure to initialise library"); return 1; } if(wsaData.wVersion != 0x0202) { Error("Wrong version used"); return 1; } cout << "Initialised\n"; SOCKET socSend = socket(AF_INET, SOCK_STREAM, 0); cout << "Socket made\n"; sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(5001); addr.sin_addr.s_addr = inet_addr("172.203.65.12"); if(bind(socSend, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) { Error("Failure to bind"); return 1; } cout << "Socket bound\n"; if(connect(socSend, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) { Error("Failure to connect"); return 1; } cout << "Connected\n"; Error("Success!"); return 0; }
void Error(char *str) { cout << str << "\n"; system("PAUSE"); WSACleanup(); } |
That's my client source.
This is the tutorial I'm using.
Rmstn1580 - January 21, 2007 10:11 PM (GMT)
I copied and pasted the code exactly in Dev-Cpp and it worked. Make sure you do this in Dev-Cpp:
1: Click on 'File > New > Project'
2: Select 'Console Application' and make sure C++ is specified as the language.
3: For name, call it 'Server'
4: Click on 'Project > Project Options'
5: Click on the 'Parameters' tab, then click the 'Add Library or Object' button
6: Make sure you're in the Dev-Cpp folder, and click on the 'lib' folder
7: Add 'libws2_32.a'
8: Compile :)
I tried compiling your client program and it compiled fine. I ran the server program then I ran the client program but every time the client program says "Failure to bind". That is the exact problem I had before. Any possible resolutions?
EDIT: I run the server and it says 'Listening...' then I run the client and the client says 'Failure to bind'. When I run the client before for server, the client says 'Failure to connect'.
biggoron - January 22, 2007 06:23 PM (GMT)
Well I did everything on the checklist. I guess I'll try copy-pasting into a new project.
I made the client to look for my IP. I leave my router on, but not my PC so that might be why it didn't connect. The server just sets up a listening port for any incoming IP on port 5001 and as far as I know listen() blocks until it receives so that'll be why it stayed there.
Failure to bind keeps coming up whenever I try it or whenever any of my friends try it. Not really sure what that's about :S
Although when you run it without the server it got to the connecting stage which means it was bound :D :D yay! And it makes sense that it won't connect then cause I didn't have anything listening for it on my router's IP on port 5001.
[edit]
Yay! Copy-pasting into a new project worked! I have a feeling it may be because I changed the name of the project (I did it from within the IDE). I don't know why that would make it fudge up like that, but it appears to be fixed.
[edit2]
Well it compiles now, but I still get errors every time with the client. I've asked quite a few people to run it (making sure to update the target IP, as it's dynamic) but every time it gets down to the binding and fails.
Rmstn1580 - January 22, 2007 11:32 PM (GMT)
Yeah that was the problem with mine. The exact problem to be precise :)
myork - January 23, 2007 02:05 PM (GMT)
| QUOTE (biggoron @ Jan 22 2007, 01:23 PM) |
Well it compiles now, but I still get errors every time with the client. I've asked quite a few people to run it (making sure to update the target IP, as it's dynamic) but every time it gets down to the binding and fails. |
You should note that if bind() returns an error (-1) Then there is an actual error code stored in the global variable errno (#include <errno.h>)
bind() can prodcue the following errors:
| CODE |
EBADF sockfd is not a valid descriptor. EINVAL The socket is already bound to an address. EACCES The address is protected, and the user is not the super-user. ENOTSOCK Argument is a descriptor for a file, not a socket. EINVAL The addrlen is wrong, or the socket was not in the AF_UNIX family. EROFS The socket inode would reside on a read-only file system. EFAULT my_addr points outside the user's accessible address space. ENAMETOOLONG my_addr is too long. ENOENT The file does not exist. ENOMEM Insufficient kernel memory was available. ENOTDIR A component of the path prefix is not a directory. EACCES Search permission is denied on a component of the path prefix. ELOOP Too many symbolic links were encountered in resolving my_addr.
|
myork - January 23, 2007 02:34 PM (GMT)
I ripped the following from my socket library. I ripped out all my error handling as it is exception based and would not fit in your code well. If you want I will post my library as it makes all socket based communications easy.
Unfortunately it is on another machine so I had to copy it by hand (no cut and paste) so there may be some typo errors. But I think the basics should be sound.
Please note the use of bzero() to make sure that the address structure is initialised correctly. Also I use 'gethostbyname()' so I can use both a name 'google.com' and a dotted decimal address '172.203.65.12'.
PS. This compiles on BSD (Apple) should work fine on all Linux/Unix may need some slight tweaking for windows.
For a client:
| CODE |
/* This way accepts both numbers and names */ struct hostent* server = gethostbyname("172.203.65.12");
struct sockaddr_in addr ={0}; bzero(reinterpret_cast<char*>&addr,sizeof(struct sockaddr_in)); bcopy(reinterpret_cast<char*>(server->h_addr), reinterpret_cast<char*>(&addr.sin_addr.s_addr), server->h_length); addr.sin_family = AF_INET; addr.sin_port = htons(<Port No>);
socketID = socket(AF_INET,SOCK_STREAM,0); /* Check for errors */
connect(socketID,reinterpret_cast<sockaddr*>(&addr),sizeof(sockaddr)); /* Check for errors */ |
For a server:
| CODE |
socketID = socket(AF_INET,SOCK_STREAM,0); /* Check for errors */
struct sockaddr_in addr = {0}; bzero(reinterpret_cast<char*>&addr,sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(<portNo>);
bind(socketID,reinterpret_cast<sockaddr*>(&addr),sizeof(addr)); /* Check for errors */ listen(socketID,<Max Connections>); /* Check for errors */
struct sockaddr_in inaddr; int addrLen = sizeof(inaddr); accept(socketID,reinterpret_cast<sockaddr*>(&inaddr),reinterpret_cast<socklen_t*>(&addrLen)); /* Check for errors */ |
adeyblue - January 23, 2007 04:04 PM (GMT)
To add the windows specifics to myork's advice:
The socket functions return SOCKET_ERROR on failure. You then need to call WSAGetLastError() instead of checking errno which will return
one of the errors hereThere's also a step-by-step to
Winsock on MSDN concluding with complete client and server code, which might help.
biggoron - January 23, 2007 07:11 PM (GMT)
Thanks myork and adeyblue, I can't believe I didn't just use WSAGetLastError in the first place :/ :(
Thanks for the link also, adeyblue, I'm sure it'll come in very useful :)