tcp/ip wrapping

I want to wrap tcp/ip with C++, but, It does not work.
Though I could establish connection but, I could not send or receive messages.
Can anyone help me?

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//tcpip.h class definition
#include <string>
#include <arpa/inet.h>

class Tcpip 
{
public:
	Tcpip(int port);
	virtual ~Tcpip();
	void send(std::string s);
	std::string recv();

protected:
	int server_fd, client_fd;
	struct sockaddr_in server_addr, client_addr;

private:
	char buffer[1024];
};

class Client : public Tcpip
{
public:
	Client(std::string ip = "127.0.0.1", int port = 2001); 
};

class Server : public Tcpip
{
public:
	Server(int port = 2001, int queue = 10);
};


//tcpip.cc class realization
#include <sys/socket.h>
#include <sys/types.h>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include "tcpip.h"
using namespace std;

Tcpip::Tcpip(int port) 
{
	memset(&server_addr, 0, sizeof(server_addr));
	memset(&client_addr, 0, sizeof(client_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
}

Tcpip::~Tcpip()
{
	close(client_fd);
}

void Tcpip::send(string s) 
{
	write(client_fd, s.c_str(), s.size()+1);
}

string Tcpip::recv()
{
	int i = read(client_fd, buffer, 1024);
	buffer[i] = 0;
	return string(buffer);
}

Client::Client(string ip, int port) : Tcpip(port) 
{
	server_addr.sin_addr.s_addr = inet_addr(ip.c_str());
	if(-1 == connect(client_fd, (sockaddr*)&server_addr, sizeof(server_addr)))
		cout << "connect() error" << endl;
	else cout << " connecting"  <<endl;
}

Server::Server(int port, int queue) : Tcpip(port) 
{
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	if(bind(server_fd, (sockaddr*)&server_addr, sizeof(server_addr)) == -1)
		cout << "bind() error" << endl;
	else cout << "binding" << endl;
	if(listen(server_fd, queue) == -1) cout << "listen() error" << endl;
	else cout << "listening" << endl;
	int cl_size = sizeof(client_addr);
	if(client_fd = accept(server_fd, (sockaddr*)&client_addr, (socklen_t*)&cl_size) == -1)
		cout << "accept() error" << endl;
	else cout << "accepting" << endl;
}


//server exe
#include <iostream>
#include <string>
#include "tcpip.h"
using namespace std;

int main()
{
	string s;
	Server sv;
while(s != "end") {
	s = sv.recv();
	cout << s;
	sv.send(s);
}
}

//client exe
#include "tcpip.h"
#include <iostream>
#include <string>
using namespace std;

int main()
{
	string s;
	Client cl;
	while(1) {
		cin >> s;
		cl.send(s);
		cout << cl.recv();
		if(s == "end") break;
	}
}

#Makefile
CFLAG = -g -std=c++11 
CC = g++
SRC = $(wildcard *.cc)
OBJ = $(patsubst %.cc, %.o, $(SRC))

all : $(OBJ)
	g++ -o cl cl.o tcpip.o
	g++ -o sv sv.o tcpip.o
	
%.o : %.cc
	$(CC) -c $< $(CFLAG)


clean : 
	rm *.o sv cl
#	./$@ 
Last edited on
I have found that Tcpip::recv() function has a problem.
The read(client_fd, ....) function at the line 67 is hanging.
In GDB, It says ../sysdeps/unix/syscall-template.S: No such file or directory..

What's wrong ?
Last edited on
Your design is wrong. The base class has everything, and thus has to duplicate the content of the derived classes. It doesn't manage the resources properly, and that's the whole point of encapsulation.

For example, if Tcpip has a server_fd and client_fd, why doesn't the destructor release both?

I's probably not worth looking any further ... but I have.

The server code is nonsense. Think about what accept() does. What happens when a client connects two or three times serially.

You probably don't need a makefile. You can build it with this (after you've deleted the makefile):
CXXFLAGS="-g -std=c++11" make cl
CXXFLAGS="-g -std=c++11" make sv

Last edited on
This is not a final code. Just a transitional code..
So not working properly on multiple connections. I just need to add some fork() after debugging this.
What I want to know is why it hangs at read function.
Do you have any idea?
And accept() works well in 1 connection after another situation.
Last edited on
And accept() works well in 1 connection after another situation.

I know, that's why I posted:
Think about what accept() does. What happens when a client connects two or three times serially.


I suggest you forget wrapping TCP in classes for now. It's a very difficult problem, must harder than it first seems.

I get it, TCP is such a pain to deal with, wouldn't it be nice if the complexity and details were wrapped up in something easy to use? The answer is, it already is.

Think of sockets as making networking as easy to use as files. So you set them up, then just read/write them in the same way you'd do with file streams. The logic goes like this.

Client Side:
1
2
3
int fd = EstablishConnection(ip_address);
write/read on fd
close(fd)


Server Side:
1
2
3
4
5
6
7
8
9
int fd = EstablistListenningConnection(ip_addresses)
while (listening)
    parallel
        int client_fd = accept(fd)
        read/write on client_fd
        close(client_fd)
    endparallel
endwhile
close(fd)


The thing to note is that each time a client connects, the server sees accecpt() return a new fd to communicate with that client on. As the server should serve more than one client at a time, you need a way to manage each connection distinctly and concurrently.
Last edited on
Thanks. There was no problem with the code. It hanged due to some other system side problem.
I don't know what it is. Do you know some way to disrupt execution by mangling the library or some other thing? If this kind of things happen again where should I see first. Because these situations happen so much to me.

I changed the code like this. Now it works very well. Even with multiple connections.

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//tcpip.h class definition
#include <string>
#include <thread>
#include <arpa/inet.h>

class Tcpip 
{
public:
	Tcpip(int port);
	virtual ~Tcpip();
	void send(std::string s);
	std::string recv();

protected:
	int server_fd, client_fd;
	struct sockaddr_in server_addr, client_addr;

private:
	char buffer[1024];
};

class Client : public Tcpip
{
public:
	Client(std::string ip = "127.0.0.1", int port = 2001); 
};

class Server : public Tcpip
{
public:
	Server(int port = 2001, int queue = 10, std::string e = "end");
	void start(std::string (*pf)(std::string s));

protected:
	std::string (*process_string)(std::string);
	void handle_connection();
	std::string end_string;
};



//tcpip.cc class realization
#include <sys/socket.h>
#include <sys/types.h>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include "tcpip.h"
using namespace std;

Tcpip::Tcpip(int port) 
{
	memset(&server_addr, 0, sizeof(server_addr));
	memset(&client_addr, 0, sizeof(client_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
}

Tcpip::~Tcpip()
{
	close(client_fd);
	close(server_fd);
}

void Tcpip::send(string s) 
{
	write(client_fd, s.c_str(), s.size()+1);
}

string Tcpip::recv()
{
	int i = read(client_fd, buffer, 1023);//error
	buffer[i] = '\0';
	return string(buffer);
}

Client::Client(string ip, int port) : Tcpip(port) 
{
	server_addr.sin_addr.s_addr = inet_addr(ip.c_str());
	if(-1 == connect(client_fd, (sockaddr*)&server_addr, sizeof(server_addr)))
		cout << "connect() error" << endl;
	else cout << " connecting"  <<endl;
}

Server::Server(int port, int queue, string e) : Tcpip(port) 
{
	end_string = e;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	if(bind(server_fd, (sockaddr*)&server_addr, sizeof(server_addr)) == -1)
		cout << "bind() error" << endl;
	else cout << "binding" << endl;
	if(listen(server_fd, queue) == -1) cout << "listen() error" << endl;
	else cout << "listening" << endl;
}

void Server::start(string (*pf)(string s))
{
	process_string = pf;
	int cl_size = sizeof(client_addr);
	while(1) {
		client_fd = accept(server_fd, (sockaddr*)&client_addr, (socklen_t*)&cl_size);
		if(client_fd == -1)	cout << "accept() error" << endl;
		else {
			cout << "accepting" << endl;
			if(fork() == 0) handle_connection();
		//	thread t(&Server::handle_connection, this);
		//	t.detach();
		}
	}
}

void Server::handle_connection()
{
	string s;
	while(s != end_string) {
		s = recv();
		send(process_string(s));
	}
	cout << "ending child" << endl;
}



//server exe
#include <string>
#include "tcpip.h"
using namespace std;

string procedure(string s)
{
	string str = "[from server] ";
	str += s + " : " + to_string(s.size());
	return str;
}

int main()
{
	Server sv;
	sv.start(procedure);
}


//client exe
#include "tcpip.h"
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char** argv)
{
	string s = "127.0.0.1";
	if(argc > 1) s = argv[1];
	Client cl(s);
	s == "";
	while(s != "end") {
		cin >> s;
		cl.send(s);
		cout << cl.recv() << endl;
	}
}
Last edited on
Topic archived. No new replies allowed.