WinSock 2 Asynchronous
Fishcake

I'm learning network programming using WinSock 2 based on a tutorial on GameDev.net

http://www.gamedev.net/reference/articles/article1059.asp

Currently, I'm just trying to create a simple console program (no window!). I want the server to be able to do stuff like send some strings to the clients and responds when a client disconnected. But I couldn't get this line to work (I'm really new to this) :

WSAAsyncSelect (s, hWnd, WM_ONSOCKET, (FD_READ | FD_CONNECT | FD_CLOSE));

I don't know where the second parameter came from... :-[ Here's my current source codes of the client and the server (no asynchronous socket yet) :

CLIENT

1#include <winsock2.h>
2#include <stdio.h>
3#include <stdlib.h>
4 
5#define WM_SOCKET WM_USER+1
6 
7 
8 
9int main()
10{
11
12 WSADATA w;
13 int error = WSAStartup (0x0202,&w);
14 if (error)
15 {
16 printf("Error: You need WinSock 2.2!\n");
17 return 0;
18 }
19 if (w.wVersion!=0x0202)
20 {
21 printf("Error: Wrong WinSock version!\n");
22 WSACleanup ();
23 return 0;
24 }
25
26 printf("WinSock Version 2.2 Initialized\n");
27
28 SOCKET s = socket(AF_INET,SOCK_STREAM,0);
29 sockaddr_in target;
30 
31 target.sin_family = AF_INET;
32 target.sin_port = htons (5555);
33 target.sin_addr.s_addr = inet_addr ("127.0.0.1");
34
35 printf("Connecting...\n");
36
37 if (connect(s, (LPSOCKADDR)&target, sizeof(target)) == SOCKET_ERROR)
38 {
39 printf("Error in connection!\n");
40 WSACleanup ();
41 return 0;
42 }
43 closesocket (s);
44 printf("Connected!\n");
45
46 while(true){
47
48 }
49 
50}

SERVER

1#include <winsock2.h>
2#include <stdio.h>
3#include <stdlib.h>
4 
5#define MAX_CLIENTS 5
6 
7int main()
8{
9
10 WSADATA w;
11 int error = WSAStartup (0x0202,&w);
12 if (error)
13 {
14 printf("Error: You need WinSock 2.2!\n");
15 return 0;
16 }
17 if (w.wVersion!=0x0202)
18 {
19 printf("Error: Wrong WinSock version!\n");
20 WSACleanup ();
21 return 0;
22 }
23
24 printf("WinSock Version 2.2 Initialized\n");
25
26 SOCKET s = socket(AF_INET,SOCK_STREAM,0);
27 sockaddr_in addr;
28 
29 addr.sin_family = AF_INET;
30 addr.sin_port = htons (5555);
31 addr.sin_addr.s_addr = htonl (INADDR_ANY);
32
33 if (bind(s,(LPSOCKADDR)&addr,sizeof(addr))==SOCKET_ERROR)
34 {
35 printf("Error: Unable to bind socket!\n");
36 WSACleanup ();
37 return 0;
38 }
39 printf("Socket binded\n");
40
41 if (listen(s,MAX_CLIENTS)==SOCKET_ERROR)
42 {
43 printf("Error: Unable to listen!\n");
44 WSACleanup ();
45 return 0;
46 }
47 printf("Listening for connections...\n");
48
49 int number_of_clients = 0;
50 SOCKET client[MAX_CLIENTS];
51 sockaddr client_sock[MAX_CLIENTS];
52 int addr_size = sizeof(sockaddr);
53 char buffer[255];
54
55 while (number_of_clients < MAX_CLIENTS)
56 {
57 client[number_of_clients] = accept (s, &client_sock[number_of_clients], &addr_size);
58
59 if (client[number_of_clients] == INVALID_SOCKET)
60 {
61 printf("Error: Unable to accept connection!\n");
62 WSACleanup ();
63 return 0;
64 }
65
66 else
67 {
68 number_of_clients++;
69 printf("Connection accepted!\n");
70 }
71 }
72
73 printf("Enough Clients!\n");
74 closesocket (s);
75
76 while(true){
77 }
78 
79}

Synapse Jumps

It seems like you're quite new to this; MSDN is your friend:
MSDN for WSAAsyncSelect

It seems like the second argument is for a window handle. Have you done windows programming at all? If not, this is gonna be a brick wall for you. I don't know if you need this line, truly. I assume you're using it so that the call to connect or accept will not be blocking (ie: it will not hang). For this you'll get to enter a magical new world: THREADS!

A thread is like another process running within your main process. In the linux world you can create a thread via the fork() function. In the Windows world, however, you have a whole nother barrel of monkeys to open to use threads. For this you'll want to look into the CreateThread Function. Just to get you started, you should note that most of the parameters to this function will be useless to you until you start getting into higher levels of threads. For now, the most important parameters are lpStartAddress (the function you want the thread to run; in other words- the main function of your thread), lpParameter (the parameter that you want to pass to the main function of your thread), and lpThreadID which is only important if you need to close your thread from within your main process.

For a great, MS filled example look here.

Fishcake

Thanks for the links! Looks like I have to learn Windows Programming first :-/

aj5555

Synapse Jumps, you make out like Windows Threads are harder than linux threads.

I use a single function to make thread. with 3 parameteres, 1 is 0, the other is a pointer to your own function, and one is the start function. Thats it!
Could it get any simplier?

Fishcake

Okay, I've found a tutorial on Windows Programming and learned a bit about the basics. The client is now using asynchronous socket. But I'm facing this problem right now. The client is able to connect to the server (I detected it using FD_CONNECT by prompting a message box) but as soon as I clicked the "OK" button on the message box, another message box saying "Unable to connect!" pops up. The second message box came from an error checking to check whether the client is able to connect to the server:

if (connect (s, (LPSOCKADDR)&target, sizeof(target)) == SOCKET_ERROR)
    {      
        MessageBox(NULL, "Unable to connect!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        WSACleanup ();
        return 0;
    }

What's the problem here? And why I can't connect in the first place? I didn't face this problem when I wrote a simple client program (without asynchronous socket).

CLIENT

1#include <windows.h>
2#include <winsock2.h>
3#include <stdio.h>
4#include <stdlib.h>
5 
6#define WM_ONSOCKET WM_USER+1
7 
8const char g_szClassName[] = "myWindowClass";
9 
10LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
11{
12 switch(msg)
13 {
14
15 case WM_ONSOCKET:
16 {
17 if (WSAGETSELECTERROR(lParam))
18 {
19 WSACleanup ();
20 return 0;
21 }
22 switch (WSAGETSELECTEVENT(lParam))
23 {
24 case FD_CONNECT : {
25 MessageBox(NULL, "Connected!", "Yay!", MB_OK);
26 } break;
27 }
28 } break;
29
30 case WM_CLOSE:
31 DestroyWindow(hwnd);
32 break;
33 case WM_DESTROY:
34 PostQuitMessage(0);
35 break;
36 default:
37 return DefWindowProc(hwnd, msg, wParam, lParam);
38 }
39 return 0;
40}
41 
42int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
43 LPSTR lpCmdLine, int nCmdShow)
44{
45 WNDCLASSEX wc;
46 HWND hwnd;
47 MSG Msg;
48 
49 wc.cbSize = sizeof(WNDCLASSEX);
50 wc.style = 0;
51 wc.lpfnWndProc = WndProc;
52 wc.cbClsExtra = 0;
53 wc.cbWndExtra = 0;
54 wc.hInstance = hInstance;
55 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
56 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
57 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
58 wc.lpszMenuName = NULL;
59 wc.lpszClassName = g_szClassName;
60 wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
61 
62 if(!RegisterClassEx(&wc))
63 {
64 MessageBox(NULL, "Window Registration Failed!", "Error!",
65 MB_ICONEXCLAMATION | MB_OK);
66 return 0;
67 }
68 
69 hwnd = CreateWindowEx(
70 WS_EX_CLIENTEDGE,
71 g_szClassName,
72 "The title of my window",
73 WS_OVERLAPPEDWINDOW,
74 CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
75 NULL, NULL, hInstance, NULL);
76 
77 if(hwnd == NULL)
78 {
79 MessageBox(NULL, "Window Creation Failed!", "Error!",
80 MB_ICONEXCLAMATION | MB_OK);
81 return 0;
82 }
83 
84 ShowWindow(hwnd, nCmdShow);
85 UpdateWindow(hwnd);
86
87 WSADATA w;
88
89 int error = WSAStartup (0x0202, &w);
90
91 if (error)
92 {
93 MessageBox(NULL, "Failed to initialize WinSock!", "Error!",
94 MB_ICONEXCLAMATION | MB_OK);
95 return 0;
96 }
97 if (w.wVersion != 0x0202)
98 {
99 MessageBox(NULL, "Wrong version of WinSock!", "Error!",
100 MB_ICONEXCLAMATION | MB_OK);
101 WSACleanup ();
102 return 0;
103 }
104
105 SOCKET s = socket (AF_INET, SOCK_STREAM, 0);
106 sockaddr_in target;
107
108 target.sin_family = AF_INET;
109 target.sin_port = htons (5001);
110 target.sin_addr.s_addr = inet_addr ("127.0.0.1");
111
112 WSAAsyncSelect (s, hwnd, WM_ONSOCKET, (FD_READ | FD_CONNECT | FD_CLOSE));
113
114 if (connect (s, (LPSOCKADDR)&target, sizeof(target)) == SOCKET_ERROR)
115 {
116 MessageBox(NULL, "Unable to connect!", "Error!",
117 MB_ICONEXCLAMATION | MB_OK);
118 WSACleanup ();
119 return 0;
120 }
121 
122 while(GetMessage(&Msg, NULL, 0, 0) > 0)
123 {
124 TranslateMessage(&Msg);
125 DispatchMessage(&Msg);
126 }
127
128 closesocket (s);
129 WSACleanup ();
130
131 return Msg.wParam;
132}

SERVER

1#include <stdio.h>
2#include <stdlib.h>
3#include <winsock2.h>
4 
5#define MAX_CLIENTS 3
6const int socket_port = 5001;
7int client_num = 0;
8int addr_size = sizeof (sockaddr);
9 
10int main ()
11{
12 WSADATA w;
13 int error = WSAStartup (0x0202, &w);
14 if (error)
15 {
16 printf ("Unable to initialize WinSock.\n");
17 return 0;
18 }
19 if (w.wVersion != 0x0202)
20 {
21 printf ("Wrong version of WinSock.\n");
22 WSACleanup ();
23 return 0;
24 }
25 printf ("WinSock 2 initialized.\n");
26
27 SOCKET s = socket (AF_INET, SOCK_STREAM, 0);
28 sockaddr_in addr;
29 addr.sin_family = AF_INET;
30 addr.sin_port = htons (socket_port);
31 addr.sin_addr.s_addr = htonl (INADDR_ANY);
32 if (bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
33 {
34 printf ("Cannot bind to port %d.\n", socket_port);
35 WSACleanup ();
36 return 0;
37 }
38 printf ("Socket binded to port %d.\n", socket_port);
39
40 if (listen (s,MAX_CLIENTS) == SOCKET_ERROR)
41 {
42 printf ("Unable to listen to port %d.\n", socket_port);
43 WSACleanup ();
44 return 0;
45 }
46 printf ("Listening for connections at port %d....\n", socket_port);
47
48 SOCKET client[MAX_CLIENTS];
49 sockaddr client_sock[MAX_CLIENTS];
50
51 while (true){
52
53 while (client_num<MAX_CLIENTS)
54 {
55 client[client_num] = accept (s, &client_sock[client_num], &addr_size);
56 if (client[client_num] == INVALID_SOCKET)
57 {
58 printf ("Unable to accept connection.\n");
59 WSACleanup ();
60 return 0;
61 }
62 else
63 {
64 printf ("A client has connected to the server.\n");
65 client_num++;
66 }
67 }
68 }
69
70 closesocket (s);
71 WSACleanup ();
72
73}

ImLeftFooted

Using threads is overkill. All the packet processing is done behind your back anyway. All your application is doing is reading memory...

Using threads for networking is like using an oversized truck to move a harddrive. Silly and a total waste of gas.

Synapse Jumps

aj: Well... pretty much everything in Windows is complicated. I mean, if you've never done any Windows programming before, anything is bound to be hard, especially something as deeply abstract and complicated as threads. Linux threads are just as abstract and complicated, but I feel their implementation just makes more sense. shrugs To each his own?

Dustin: Oh please. If he wants to learn how to do network programming he damn sure well better know how to use threads. Maybe he doesn't need them just yet, but its a really useful tool to have in your 'programming arsenal.' I mean, unless you just want to serve one client forever, or only wait for those blocking accept calls to serve more than one client.

Fish: I think you're thinking about this a little backwards. Usually servers are the heavily asynchronous sides of the networked world. They both listen for incoming connections and serve information to their clients. Their trick is that they often accept and serve several clients simultaneously- a feat nearly impossible without the helping hands of threads. What you're trying to do here really doesn't require asynchronous activity. I suppose I should apologize for leading you astray with threads, but, as mentioned above: they're terribly useful and a great thing to know about.

Anyways, I think I'vefigured out why you're getting this strange error. Check out the MSDN on connect. Specifically the part about the return values:

MSDN said:

On a blocking socket, the return value indicates success or failure of the connection attempt.

With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return SOCKET_ERROR, and WSAGetLastError will return WSAEWOULDBLOCK. In this case, there are three possible scenarios...

As you can see, your socket is nonblocking, and therefore will force a return of SOCKET_ERROR. Not that you really have an error, just that you can't connect at just that moment. Get it? You're on the right track, though, for sure.

Fishcake

I don't really get what you're saying but the problem was solved when I changed the arrangement of the codes :

if (connect (s, (LPSOCKADDR)&target, sizeof(target)) == SOCKET_ERROR)
    {      
        MessageBox(NULL, "Unable to connect!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        WSACleanup ();
        return 0;
    }

WSAAsyncSelect (s, hwnd, WM_ONSOCKET, (FD_READ | FD_CONNECT | FD_CLOSE));

aj5555
Quote:

Well... pretty much everything in Windows is complicated.

No its not.

Quote:

I mean, if you've never done any Windows programming before, anything is bound to be hard

If you've never done any Windows programming, its bound to be UNKNOWN, it might be easy, it might be hard. Is everything new to you difficult? Have you a learning disability?

Quote:

especially something as deeply abstract and complicated as threads.

what is so complicated about one very simple idea.. instead of having one piece of code running, you have several. What is so hard to comprehend about that?
Complicated? There is only 1 rule for threads. "lock shared memory" its not rocket surgery. ::)

Synapse Jumps

Fishcake: Ya, that would fix the problem. When your sockets are blocking, ie: synchronous, if you ask them to connect, they'll keep trying to connect untl it happens or times out, without halting to let ANYTHING else in your program happen. When your sockets are asynchronous, ie: nonblocking, if you ask them to connect, they will immediately return a value of SOCKET_ERROR so as to not continue blocking your programs execution. They will, however, connect, simply in the background where they don't have to keep your code from executing. This is most likely accomplished via some sort of thread or seperate Windows process.

aj: Damn, dude. Lets argue semantics a little more, shall we? Yes, new things are generally more difficult for me to grasp than things that I currently have a good understanding of. Damn this learning disability of mine!

the false AJ said:

what is so complicated about one very simple idea.. instead of having one piece of code running, you have several. What is so hard to comprehend about that?
Complicated? There is only 1 rule for threads. "lock shared memory" its not rocket surgery.

Right. That's all there is to threads. You don't need to specify a stack size for them, nor do you need to free their memories. Opening and closing several threads at run-time, that's not important, or complicated! Just two pieces of code running, right? An operating system is just several pieces of code running at once; what's so hard about that? When do we get AJOS? Will the information provided be in sentence fragments and structured as grammatical nightmares? Honestly, writing is simple: just put letters together and punctuate it correctly. Is everything simple for mankind difficult for you? Really, its not rocket science.

PS: Speaking of rockets, please preform surgery on a rocket. We're seriously lacking in Darwin Awards on Allegro.cc

Fishcake

Following Beej's Guide to Network Programming, I was able to turn the server into non-blocking using the select() function.

How do I use select() to turn the client into non-blocking ( without using WSAAsyncSelect() ) so that send() and recv() do not block? Or should I just stick to WSAAsyncSelect()? (I hate using WINAPI with allegro :-[)

Synapse Jumps

Umm... If you've got the server you should be able to get the client. You just have to check in your main loop if the socket is ready to recieve stuff... Is send even blocking? Anyways this is pseudocode for it:

1#include <winsock2.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <fcntl.h>
5 
6int main()
7{
8
9 WSADATA w;
10 int error = WSAStartup (0x0202,&w);
11 if (error)
12 {
13 printf("Error: You need WinSock 2.2!\n");
14 return 0;
15 }
16 if (w.wVersion!=0x0202)
17 {
18 printf("Error: Wrong WinSock version!\n");
19 WSACleanup ();
20 return 0;
21 }
22
23 printf("WinSock Version 2.2 Initialized\n");
24
25 SOCKET s = socket(AF_INET,SOCK_STREAM,0);
26 fcntl(s, F_SETFL, O_NONBLOCK);
27 sockaddr_in target;
28 
29 target.sin_family = AF_INET;
30 target.sin_port = htons (5555);
31 target.sin_addr.s_addr = inet_addr ("127.0.0.1");
32
33 printf("Connecting...\n");
34
35 if (connect(s, (LPSOCKADDR)&target, sizeof(target)) == SOCKET_ERROR)
36 {
37 printf("Error in connection!\n");
38 WSACleanup ();
39 return 0;
40 }
41 printf("Connected!\n");
42
43 fd_set readfds, writefds;
44 FD_ZERO(&readfds); FD_ZERO(&writefds);
45 FD_SET(s, &readfds); FD_SET(s, &writefds); //add our socket to the two sets sets we'll send to select
46 struct timeval tv;
47 tv.tv_sec = 0; tv.tv_usec = 50;
48 
49 while(true){
50 select((int)s+1, &readfds, &writefds, NULL, &tv); //check if the socket can be read/written
51
52 if (FD_ISSET(s, &readfds)) //the socket is ready to recieve
53 recv(stuff);
54 else if (FD_ISSET(s, &writefds)) //the socket is ready to write stuff.... but it should always be...
55 send(stuff);
56 }
57 
58}

Fishcake

fcntl(s, F_SETFL, O_NONBLOCK);

I have problem with this line. I have included fcntl.h, but F_SETFL and O_NONBLOCK are not defined :-[. Oh wait, even the function itself is not defined.
When I commented the line out, the main loop ran but recv() was not called. And then I tried changing the last parameter of select() to NULL. recv() still blocks.

------------------------------------------------------------------------------------

About my server, I want to allow only 2 clients to connect. If an extra client tries to connect, the server will not accept it. But if one or more connected client disconnected, the server will accept connections again. How do I do that? Currently, it accepts every connection. Here's the source code :

1#include <winsock2.h>
2#include <stdio.h>
3 
4#define PORT 8000
5#define MAX_CLIENTS 2
6int client_num = 0;
7WSADATA wsadata;
8fd_set master;
9fd_set read_fds;
10sockaddr_in myaddr;
11sockaddr_in remoteaddr;
12int fdmax;
13SOCKET listener;
14int newfd;
15char buf[256];
16int nbytes;
17int yes = 1;
18int addrlen = sizeof(remoteaddr);
19int i;
20int j;
21 
22int main()
23{
24
25 int error = WSAStartup (0x0202, &wsadata);
26
27 if (error)
28 {
29 printf("Unable to initialize WinSock.\n");
30 return 0;
31 }
32 if (wsadata.wVersion != 0x0202)
33 {
34 printf("Wrong version of WinSock.\n");
35 WSACleanup ();
36 return 0;
37 }
38
39 printf("WinSock initialized.\n");
40 
41 FD_ZERO(&master);
42 FD_ZERO(&read_fds);
43 
44 if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
45 printf("Unable to create socket.\n");
46 WSACleanup ();
47 return 0;
48 }
49
50 printf("Listener socket created.\n");
51
52 port_input:
53 int myport;
54 printf( "Enter a port number : " );
55 scanf( "%d", &myport );
56 if( myport <= 0)
57 {
58 printf( "Invalid port number.\n" );
59 goto port_input;
60 }
61 
62 myaddr.sin_family = AF_INET;
63 myaddr.sin_port = htons(myport);
64 myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
65 memset(myaddr.sin_zero, '\0', sizeof myaddr.sin_zero);
66
67 if (bind(listener, (LPSOCKADDR)&myaddr, sizeof(myaddr)) == SOCKET_ERROR) {
68 printf("Unable to bind to port %d.\n", myport);
69 WSACleanup ();
70 return 0;
71 }
72
73 printf("Listener socket binded to port %d.\n", myport);
74 
75 if (listen(listener, MAX_CLIENTS) == -1) {
76 printf("Unable to listen.\n");
77 WSACleanup ();
78 return 0;
79 }
80 
81 printf("Listening for connections....\n");
82 
83 FD_SET(listener, &master);
84 fdmax = listener;
85 
86 while(true)
87 {
88 read_fds = master;
89 if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
90 return 0;
91 }
92
93 /* for loop starts here */
94 for(i=0; i <= fdmax; i++) {
95 if(FD_ISSET(i, &read_fds))
96 {
97 if(i == listener)
98 {
99 if ((newfd = accept(listener, (LPSOCKADDR)&remoteaddr, &addrlen)) == SOCKET_ERROR)
100 {
101 printf("Unable to accept connection.\n");
102 return 0;
103 } else {
104 FD_SET(newfd, &master);
105 if (newfd > fdmax) {
106 fdmax = newfd;
107 }
108 printf("Accepted a new connection from %s on " \
109 "socket %d\n", \
110 inet_ntoa(remoteaddr.sin_addr), newfd);
111 client_num++;
112 printf("Number of clients : %d\n", client_num);
113 }
114 } else {
115 nbytes = recv(i, buf, sizeof(buf), 0);
116 if(nbytes == 0 || nbytes == INVALID_SOCKET)
117 {
118 printf("Socket %d hung up\n", i);
119 closesocket(i);
120 FD_CLR(i, &master);
121 client_num--;
122 printf("Number of clients : %d\n", client_num);
123 }
124 }
125 }
126 }
127 /* for loop ends here */
128
129 }
130
131 closesocket (listener);
132 WSACleanup();
133 return 0;
134
135}

Synapse Jumps

Indeed, it looks like fcntl is the Linux version of this function call. The windows version is ioctlsocket. As for recv() not running: Well... Yah. Did you even read the documentation on select() or the Beej guide? The way that code is set up, the socket MUST have something to read (and select() must say it does) before it will actually receive anything. As for setting the last parameter of select() to NULL:

MSDN said:

timeout

Maximum time for select to wait, provided in the form of a TIMEVAL structure. Set the timeout parameter to null for blocking operations.

It would seem that it is not recv() that's blocking, but rather select(). To fix these problems, you need to set the socket to nonblocking mode with the Windows function call (the one mentioned above; there's a tutorial further down on the MSDN page). Then everything should fall into place.

As for your server:

//the line
if(i == listener)
//should be
if(i == listener && num_clients < 2)

ImLeftFooted
Synapse said:

I mean, unless you just want to serve one client forever, or only wait for those blocking accept calls to serve more than one client.

If you believe threads to be the ideal solution for multiple clients you should not be giving out advice.

It is not.

Fishcake

if(i == listener && num_clients < 2)
It didn't work. The third client was unable to connect but it didn't show "Unable to connect" error. Plus, when the third client tried to connect, the num_clients was reduced by 1. So I ended up with num_clients = 1 eventhough there were two clients connected. And the server was not accepting any connections after that, even when a connected client disconnected. I hope you understand what I'm trying to say. :P

--------------------------------------------------------

Okay, I know how to send strings, but I have problem sending other stuff like floats and doubles. Following Beej's Guide, I tried to send double through the second method :

double d = 3490.15926535;
send ( s, &d, sizeof ( d ), 0 );  /* DANGER--non-portable! */

But heck, the second parameter only accept char. ???

Edgar Reynaldo

You're only sending a group of bytes at a time , that's why it only accepts a char* , use something like

reinterpret_cast<char*>(&d)

for the char* parameter and see if it likes that better.

Synapse Jumps

Dustin: I did misunderstand his OP and I already said that I shouldn't have suggested threads. The fact still stands, however, that they are terribly useful and worth learning about with network programming. They are a viable solution to several problems that this kind of coding presents.

Fish: Oops! Indeed. Try this one:

//change this line
if ((newfd = accept(listener, (LPSOCKADDR)&remoteaddr, &addrlen)) == SOCKET_ERROR)
//to this:
if (num_clients > 1 || (newfd = accept(listener, (LPSOCKADDR)&remoteaddr, &addrlen)) == SOCKET_ERROR)

And ya, for that send() you need some sort of cast. I don't remember all the C++ cast types, but I think you could just use a standard C-cast if you want.
send ( s, (char *)&d, sizeof ( d ), 0 );

Fishcake
//change this line
if ((newfd = accept(listener, (LPSOCKADDR)&remoteaddr, &addrlen)) == SOCKET_ERROR)
//to this:
if (num_clients > 1 || (newfd = accept(listener, (LPSOCKADDR)&remoteaddr, &addrlen)) == SOCKET_ERROR)

Maybe it would work, but I found a way to prevent extra clients from connecting. All I did was close the listener socket when client_num == MAX_CLIENTS and open it back when client_num < MAX_CLIENTS. It's working perfectly now.

Okay, now I stumble upon another problem. Right now I'm trying to develop a network pong game based on my MiniPong game. When the client presses the UP/DOWN directional button, it will send a message to the server, telling it to increase/decrease the y-velocity of the paddle. The server will then process the data ( adds the y-vel to the y-coor, multiply y-vel with friction, check collision, etc... ). I got this part working.

In the next stage, the server will send the y-vel of player 1 ( the client itself ) and also the y-vel of player 2 ( the other client ) back to both the clients ( or should I send the y-coordinates instead? ). Here's my source codes, after reading Beej's Guide ( I'm not sure whether I'm following it correctly :P ) :

/* -----------  Server  -------------- */
size_t packetsize;
//If client is player 1
if ( j == 0 ) packetsize = pack ( sendBuff, "ff", player_1.dy, player_2.dy );

//If client is player 2
else packetsize = pack ( sendBuff, "ff", player_2.dy, player_1.dy );

//I don't understand what's the use of this
packi16 ( sendBuff + 1, packetsize );

//Send it!
send ( csockets[j], reinterpret_cast<char*>( &sendBuff ), sizeof ( sendBuff ), 0 );

/* -----------  Client  -------------- */
unsigned char recvBuffer[1024];
int serverErr = recv ( s, reinterpret_cast<char*> ( &recvBuffer ), sizeof ( recvBuffer ), 0 );
if ( serverErr == 0 || serverErr == INVALID_SOCKET )
{
    MessageBox ( hWnd, "Disconnected from server!", "Error",
                   MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL );
    SendMessage ( hwnd, WM_DESTROY, wParam, lParam );
else
{
    unpack ( recvBuffer, "ff", &player_1.dy, &player_2.dy );
}

When I test them, the clients hang! ??? I need to resolve this problem before moving on to the ball. ( a pong is no pong without the ball :) )

[EDIT]
Oh wait, I think send() is blocking. Dang, I hate this...:'( I'll try and fix it.

[EDIT2]
Fixed it. But the game is running darn slow. I think I should use UDP. :-X

Don Freeman

I will answer...even if cookies have already been handed out!::)

I have attached a crude, but working example on how to use socket programming and allegro in a console. It is called MyChat, but it is not a chat program. I decided to change it to see how fast the network code was. I have made several improvements since (the power of knowledge::)), but this should help you anyway. I set the gfx mode to show the output, but you could rip the networking code out and just make it a totally console app. The code is FAR from perfect, so don't expect any magical jellybeans or anything.:P This should help you some. Beej's guide and these have really helped:

http://www.sockets.com/a_c2.htm
http://www.sockets.com/winsock.htm
http://tangentsoft.net/wskfaq/examples/basics/ though tangetsoft.net seems to be down right now...maintenances?

I am still learning all of the little "fun" stuff about winsock, but I can help you a bit. Enjoy the code, and the journey...;)

Thread #594471. Printed from Allegro.cc