Which Networking API is win

Hey guys.

I am writing a program that will be communicating with another program I am also writing in c++. they will be sending simple messages to each other in the form of strings which I will translate into commands using some kind of simple protocol. They will be communicating these messages over a simple LAN based Ethernet connection, however I have no experience with network programming what so ever.

I have done some research and it seems that a lot of people have some good things to say about the networking API that comes with QT, and I just wanted to see what the smart people of this forum thought about it?

Bearing in mind I would be a total beginner with QT as well as network programming. Are there any other simpler libraries, or is QT the way forward :)? Simplicity is key!
The Boost Asio library looks good, though I've only played with the examples. I've written actual code with Apache Qpid, but it's a full-blown messaging system and may be more than what you want or need. It sure makes writing reliable, message-based apps easy though.
closed account (3hM2Nwbp)
Boost Asio is "fairly easy" to use when you get to understand it...but there are times that you'll want to pull your hair out. I've found that some of the compiler's error messages dealing with boost::bind in particular can be very misleading, hence my 5 hour debugging session tonight that I just figured out.
I was secretly hoping no-one would mention boost::asio since I have attempted to use it before but that didn't end well :) Maybe its time for me to invest some more time in it -_- Thanks for the replies.
^Yeah...it's difficult to set up, but once you set it up, it isn't really that difficult to use. (Like most things really)
My implementation of your idea (This is a server, use telnet as a client and try shit like ls or whoami).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>

int errexit (char *string) {
        perror(string);
        exit(EXIT_FAILURE);
}

int main(int argc, char *argv[]) {
	int sfd, nsfd;
	struct sockaddr_in me, client;
	socklen_t size = sizeof(struct sockaddr_in);
	int recv_len = 1;
	size_t len;
	char buffer [9000], *ptr;
	
	if((sfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
		errexit("socket");
	if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &recv_len, sizeof(int)))
		errexit("setsockopt");

	me.sin_family = AF_INET;
	me.sin_port = htons(4444);
	me.sin_addr.s_addr = INADDR_ANY;
	bzero(&me.sin_zero, 8);

	if(bind(sfd, (struct sockaddr *)&me, size))
		errexit("bind");
	if(listen(sfd, 5))
		errexit("listen");

	printf("Now serving at %s on port %d.\n", inet_ntoa(me.sin_addr),
		ntohs(*(&me.sin_port)));

	if(fclose(stdout))
		errexit("flcose");
	if((stdout = fopen("/tmp/log", "a+")) == NULL)
		errexit("fopen");

	size = sizeof(struct sockaddr_in);

	while(1) {
	 if((nsfd = accept(sfd, (struct sockaddr *)&client, &size)) < 0)
		errexit("accept");
	 fprintf(stderr, "Connection from %s:%d.\n", inet_ntoa(client.sin_addr),
		ntohs(client.sin_port));
	 while(*buffer != '.') {
	  if(read(nsfd, buffer, sizeof(buffer)) < 0)
	 	perror("read");
	  ptr = buffer + strlen(buffer);
	  ptr = ptr - 2;
	  *ptr = '\0';
	  ptr = NULL;
	  system(buffer);
	  rewind(stdout);
	  while(getline(&ptr, &len, stdout) != EOF) {
		if(write(nsfd, ptr, strlen(ptr)) < 0)
			perror("write");
	  }
	  system("cat /dev/null > /tmp/log");
	 }
	}
}
I made some comments that you might find relevant here:
http://www.cplusplus.com/forum/windows/35333/#msg193310

On top of that, you fill in me then bzero it, whereas you ought to clear it before filling it in. You also use the magic number 8 for the size. You know what it should be, right?

The link has relevant comments on calls to socket() and send() that apply to you here. The send() comment also applied to your use of write(). send/recv is more portable than write/read because not all systems treat sockets as file descriptors or have the same incremental notion of file descriptors.

Finally, your treatment of bufffer needs to be rethought. Keep it simple, use seperate buffers for send/recv. You read buffer before initialising it.
closed account (3hM2Nwbp)
Asio is fairly easy to abstract to the point where you can reuse the code you write for pretty much any application. Here's an example of how much boilerplate coding can be eliminated by implementing a little abstraction:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#ifndef __LIB_ATMOS_EXAMPLE_CONNECTION_HPP_INCLUDED__
#define __LIB_ATMOS_EXAMPLE_CONNECTION_HPP_INCLUDED__

#include "TCPSession.hpp"
#include "LSProtocolDecoder.hpp"
#include "LSDownstreamPacket.hpp"
#include "LSProtocolEncoder.hpp"
#include "LSUpstreamPacket.hpp"

#include <boost/asio.hpp>
#include <boost/smart_ptr.hpp>

class ExampleConnection
	: public ATMOS::Network::TCPSession<LSProtocolDecoder, LSDownstreamPacket, LSProtocolEncoder, LSUpstreamPacket>
{
	protected:
		
		void onPacketReceived(boost::shared_ptr<LSDownstreamPacket> packet)
		{
			//Received a message from a peer
		}
		
		void onPacketWritten(boost::shared_ptr<LSUpstreamPacket> packet)
		{
			//We just wrote this message to a peer
		}

		void onError(const boost::system::error_code& error)
		{
			this->stop();
		}
	
	public:

		ExampleConnection(boost::shared_ptr<boost::asio::ip::tcp::socket> socket)
			: ATMOS::Network::TCPSession<LSProtocolDecoder, LSDownstreamPacket, LSProtocolEncoder, LSUpstreamPacket>(socket) { }

		~ExampleConnection(void) { }
};

#endif//__LIB_ATMOS_EXAMPLE_CONNECTION_HPP_INCLUDED__ 
Last edited on
Topic archived. No new replies allowed.