Archive for C++
Simple Client in C++
Posted by: | CommentsAlthough a TCP client is fundamentally different from a TCP server, setting up the socket is very much the same. For a server, we called these methods in this order:
socket()→bind()→listen()→accept(), followed by sequences of read() and write().
For a client we will call these methods in this order:
socket()→connect(), followed by sequences of write() and read() depending on what your server does.
To illustrate, I will create a simple HTTP client in C++, which has the following usage:
client www.googolflex.com
It will then make a connection on port 80 of the server specified at the command line, send an HTTP 1.1 request, and then dump the response to the console.
It uses the following variables:
int sock; struct sockaddr_in client; int PORT = 80;
The first thing to do is initialize the socket structure, for this we need the IP address of the host. You can use the gethostbyname(char *) function to do that, which passes back a hostent structure. I have encapsulated the socket setup into a method, which shows how to extract the necessary values from the hostent struct, here:
void setupSocket(char* hostname) {
struct hostent * host = gethostbyname(hostname);
if ( (host == NULL) || (host->h_addr == NULL) ) {
cout << "Error retrieving DNS information." << endl;
exit(1);
}
bzero(&client, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons( PORT );
memcpy(&client.sin_addr, host->h_addr, host->h_length);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
cout << "Error creating socket." << endl;
exit(1);
}
}
If this method executes correctly, then we have a socket, and an address structure that we can use to call connect() with. Here is my encapsulating method:
void connectToHost(char* hostname) {
if ( connect(sock, (struct sockaddr *)&client, sizeof(client)) < 0 ) {
close(sock);
cout << "Could not connect to " << hostname << endl;
exit(1);
}
}
Finally, we can call send()/write() and read()/recv(). This is where your protocol would be implemented, if you were to modify this for use with something other than simple HTTP requests. Here my sendRequest() and getResponse() methods:
void sendRequest(char* hostname) {
string request = "GET / HTTP/1.1\r\nHost: ";
request+= string(hostname);
request += "\r\n\r\n";
if (send(sock, request.c_str(), request.length(), 0) != (int)request.length()) {
cout << "Error sending request." << endl;
exit(1);
}
}
void getResponse() {
char cur;
while ( read(sock, &cur, 1) > 0 ) {
cout << cur;
}
}
In main() I call these four methods in sequence, passing in the hostname parameter where needed. And that’s it. The full source is included at the end of the post.
Socket connections really aren’t that difficult once you’ve done it several times. Next I will be demonstrating how to set up a simple client in Flex using a client. Many scripting languages have abstracted away much of the difficulty surrounding socket connections (as we will see with Flex) leaving you to focus on implementing your protocol.
Download the source for simpleclient here. It can be compiled as follows:
g++ -Wall -o client simpleclient.cpp

