2017-05-30 19:52:14

Hello all,
so, I made a progress with my bgt_kit package for c++, many things needed to develop audiogames are much much easyer than in default state for me, like playing and positioning sounds, grabbing keyboard input, reading and saving files etc. Only feature that missing me at this moment is good network system, like thatone in bgt.

i looked to the native c++ winsocks api, and refuted it after few moments. Nothing in bad, but hundreds of lines to make echo server with ability to connect only one client, well, that is really not for me. big_smile

I saw that there are many libraryes to manage this, but whichone is best? my requirements are that it should be simple, with less of writing and clear code, but still powerfull, like in bgt. I would like to create games like STW, UP, SBYW etc. with it. I have experience with mp systems in bgt, I created few games working as that mentioned above, but I don't know which library can offer to me possibilities like bgt network object. Can you please suggest me some options?

Yeah, and it shoult to be compilable on Windows, I tried to compile Asio network library to see, how it works and have not success, I don't understand why people are using that linux automated makefiles and not simple .bat or .sh scripts, compilation is than really horrible stuff on Windows.

Thanks.

Best regards

Rastislav

2017-05-30 20:47:01

hello,
eNet is the network library used in bgt
it works in windows and it is a wrapper around operating system's socket api
it is based on udp
another option is boost.asio (the asio which is the part of  boost distribution) which  if you want to use it it is fine  because it supports both tcp and udp sockets
another option is ace, which i dont know really about it
poco is another option, as it shows it is fine

2017-05-30 21:48:06

I'm a bit confused here; BGT's networking library is not at all

2017-05-31 01:30:11 (edited by visualstudio 2017-05-31 01:30:53)

sorressean wrote:

I'm a bit confused here; BGT's networking library is not at all

@sorressean, yes, bgt use's eNet for its network stuff or better to say, the network class is a wrapper around eNet

2017-05-31 21:39:50

@2 and 4, how did you even discover this information? I doubt Philip ever told us what network library he used. I guarantee you he used winsock.
@Rastislav Kiss, you can make an echo server using C using POSIX. Problem in this is that it only works on POSIX-based systems. Either way it looks like this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

#define MAX_ENQUEUED 20
#define BUF_LEN 256
#define PORT_STR "12321"

/* ------------------------------------------------------------ */
/* How to clean up after dead child processes                   */
/* ------------------------------------------------------------ */

void wait_for_zombie(int s)
{
    while(waitpid(-1, NULL, WNOHANG) > 0) ;
}

/* ------------------------------------------------------------ */
/* Core of implementation of a child process                    */
/* ------------------------------------------------------------ */

void echo_lines(int csock)
{
    char buf[BUF_LEN];
    int r;

    while( (r = read(csock, buf, BUF_LEN)) > 0 ) {
        (void)write(csock, buf, r);
    }
    exit(EXIT_SUCCESS);
}

/* ------------------------------------------------------------ */
/* Core of implementation of the parent process                 */
/* ------------------------------------------------------------ */

void take_connections_forever(int ssock)
{
    for(;;) {
        struct sockaddr addr;
        socklen_t addr_size = sizeof(addr);
        int csock;

        /* Block until we take one connection to the server socket */
        csock = accept(ssock, &addr, &addr_size);

        /* If it was a successful connection, spawn a worker process to service it */
        if ( csock == -1 ) {
            perror("accept");
        } else if ( fork() == 0 ) {
            close(ssock);
            echo_lines(csock);
        } else {
            close(csock);
        }
    }
}

/* ------------------------------------------------------------ */
/* The server process's one-off setup code                      */
/* ------------------------------------------------------------ */

int main()
{
    struct addrinfo hints, *res;
    struct sigaction sa;
    int sock;

    /* Look up the address to bind to */
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;
    if ( getaddrinfo(NULL, PORT_STR, &hints, &res) != 0 ) {
        perror("getaddrinfo");
        exit(EXIT_FAILURE);
    }

    /* Make a socket */
    if ( (sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1 ) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    /* Arrange to clean up child processes (the workers) */
    sa.sa_handler = wait_for_zombie;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if ( sigaction(SIGCHLD, &sa, NULL) == -1 ) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    /* Associate the socket with its address */
    if ( bind(sock, res->ai_addr, res->ai_addrlen) != 0 ) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    freeaddrinfo(res);

    /* State that we've opened a server socket and are listening for connections */
    if ( listen(sock, MAX_ENQUEUED) != 0 ) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    /* Serve the listening socket until killed */
    take_connections_forever(sock);
    return EXIT_SUCCESS;
}

Or you can use sockets with Boost.Asio:

//compile with g++ main.cpp -lboost_system -pthread 

#include <boost/asio.hpp>

int main()
{
boost::asio::io_service io_service;
boost::asio::ip::tcp::socket sock(io_service);
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query("localhost", "4321");

boost::asio::connect(sock, resolver.resolve(query));
boost::asio::write(sock, boost::asio::buffer("Hello world socket\r\n"));

return 0;
}

or even:

//compile with g++ main.cpp -lboost_system -pthread 

#include <boost/asio.hpp>
using namespace boost::asio;

int main()
{
  io_service io_service;
  ip::tcp::socket sock(io_service);
  ip::tcp::resolver resolver(io_service);
  ip::tcp::resolver::query query("localhost", "4321");

  connect(sock, resolver.resolve(query));
  write(sock, buffer("Hello world socket\r\n"));

  return 0;
}

There are many other ways to do this. (I got this material from http://rosettacode.org/wiki/Echo_server and http://rosettacode.org/wiki/Sockets); go to http://rosettacode.org/wiki/Category:C++ for other ideas.

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2017-06-01 02:11:03

@Ethin, look at credits topic in the bgt's manual
also another library is exist if you are using sdl, sdl_net seems fine
enetpp is another option whichis discontinued, (although it seems that enet has been discontinued also)
enet itself uses winsock in windows
for simple tasks winsock seems easy to use but for such tasks that requires lots of packets, it seems a little bit harsh

2017-06-01 04:42:27

The reason it's so harsh is because it's mainly for C developers. It's not meant for object-oriented programming. I know that others are trying to adapt it though.

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2017-06-01 07:16:57

eNet is also isnt made for oop programming!
it is holy written in c

2017-06-01 08:09:00

Considering the fact that I've never used the library before, I'll have to take your word on that one. I, personally, still prefer libraries like boost.asio or other wrapper libraries to help me do these kinds of things. I especially like Go's net library -- things get quite easy there. A simple web server that just prints "Testing123!" looks like:

package main

import (
  "fmt"
  "log"
  "net/http"
)

func main() {
  http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintln(w, "Testing123!")
  })
  log.Fatal(http.ListenAndServe(":8080", nil))
}

But we're not talking about web servers, we're talking about sockets and network programming. See, the reason manipulating sockets is so difficult is that your directly manipulating the transmissions of the data: the packets, the server and the receiver, the data within those packets, etc. You have full control over what happens to the data. This is why libraries like Winsock and POSIX are so complicated -- you manipulate everything and have full control over what happens.

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2017-06-02 00:21:09 (edited by sorressean 2017-06-02 00:22:26)

The posix server you posted literally is just an exercise in copypasting code. It won't run on windows (pretty obvious by the unistd.h include, and the code is fairly awful at best. Winsock or the basic socket libraries don't get harder with more packets, if you know how to write decent applications. Your socket-handling functions should be written in a networking layer of your game, which other layers and/or modules should be calling to. If you have multiple types of packets, you should have something that can be wrapped up in a struct, consider a union with a packet type and the packet header, or you should have something that can easily build and dump packets into a buffer and then get it back.
Network programming is hard, but not really for any of the reasons anyone has mentioned here. It's hard because you need to be very specific about your data, you need to handle a lot of edgecases and it's hard to test in many instances. Depending on what I'm doing, I use sockets at a low level or I use boost::asio. Just because the library isn't OOP doesn't mean more programming, nor does it mean you can't easily wrap your own code in objects around it. It's really in how you approach it.

I've got a game protocol which works great for multiplayer games. Packets are small, sending of individual clusters is easy and it has a really small overhead. It took me about 12 hours to write and it's about 4.5k lines of code or so, but I can literally plug it in to any game I want because it's a library. it uses posix sockets (and handles winsock too) so it's cross platform. The hardest part was getting the UDP right. Bit manipulation and understanding variable datatypes is going to be your friend. A basic ack packet is 4 bytes, for example. Many commands can be included in that 4 byte payload. I'm trying to make it smaller and may be redesigning the protocol, but for now it's really cool. Something you should also consider if you use UDP is creating a snapshot sort of system so that you can just send deltas of maps and the like. You can easily merge your deltas when to many pile up and just revert back to a basic map with no deltas. This is how I handle sending large maps back and forth. There is also some compression that happens behind the scenes, but really the trick here is the delta system.
HTH,

2017-06-02 02:56:56

hello,
so you've wrote a wrapper around winsock
otherwise it becomes harder and harder (beside compression and decompression) although compression is an easy thing with zLib, but working  with packets can anoy you sometime
also, eNet has a wrapper which i want to work more on it if i have time, and added compression support for it, this is called enetpp and i've forked it to my account
just checkout my github if you want to get it

2017-06-02 16:15:47

Yes, sort of. I wrote a wrapper for my purposes around sockets, which is literally what you should do at any level if you're working with winsock. I'm not really sure why winsock gets

2017-06-03 00:54:47 (edited by Rastislav Kish 2017-06-03 01:10:43)

Hello,
@Visualstudio: Thank you in advance, it looks like Enet is exactly what I am looking for. I have readed tutorial to the point of server and client initialization, after it I found that I am unable to compile it because of unreferenced methods in a static library lol. Hovever there is probably problem on my site, I will search how to fix it, important is that syntax is nice.

sorressean wrote:

It took me about 12 hours to write and it's about 4.5k lines of code or so, but I can literally plug it in to any game I want because it's a library.

Well, 12 hours when you know how to do it. For me, few days would to be only about learning how packets and theyr coding works, next few days of understanding how to write it to winsocks and finally a lot of testing time, after it all I also don't must have the most effective result. Question is why to do it? Why to waste time for writing something, that someone already wrote and released as a free library?
Another reason is that winsocks need for every connection a new thread as I know. I can't make multythread apps in c++, not in Windows, in Linux the situation is easy, you can use fork and related methods, but on Windows there are just few apis and all more complicated, so I using Python for this when needed. smile

Yeah, and winsocks requires lots of writing what I don't like in wrappers too, they are hard to edit in that case.

Best regards

Rastislav

2017-06-03 03:49:55

hello
first, for fixing undefined references:
if you are using MinGW, first link enet with -lenet then link winsock with -lws2_32
if you are using msvc, link enet (enet.lib) and winsock (ws2_32.lib)
i also link mswsock and wsock32
and what are your linker errors if it doesnt fix it?

2017-06-04 02:28:28

YOu keep spewing forth misinformation, so I'll try to correct it yet again. Yes, it would take someone a couple days to learn Winsock, but it's the difference in beting a compitant developer and understanding what's going on under the hood and just mindlessly using libraries, then having problems when they don't work. Second, you do not need a thread per connection in any platform, nor do you need to fork. You can use threads to manage groups of connections, but if you can't handle work with the posix sockets library you're certainly not ready for concurrent programming.