GET and PUT commands with C++ Server-Client - c++

I'm trying to create a server, client put and get method but I don't really know where to start, how do I make the server run the commands I process. Any help would be much appreciated.
Client file
void Copy(char *filename1,char *filename2);
int main(int argc, char **argv)
{
if(argc == 3)
{
int Sockfd;
sockaddr_in ServAddr;
hostent *HostPtr;
int Port = atoi(argv[2]);
int BuffSize = 0;
// get the address of the host
HostPtr = Gethostbyname(argv[1]);
if(HostPtr->h_addrtype != AF_INET)
{
perror("Unknown address type!");
exit(1);
}
memset((char *) &ServAddr, 0, sizeof(ServAddr));
ServAddr.sin_family = AF_INET;
ServAddr.sin_addr.s_addr = ((in_addr*)HostPtr->h_addr_list[0])->s_addr;
ServAddr.sin_port = htons(Port);
// open a TCP socket
Sockfd = Socket(AF_INET, SOCK_STREAM, 0);
// connect to the server
Connect(Sockfd, (sockaddr*)&ServAddr, sizeof(ServAddr));
char userI[256];
// write a message to the server
int dupSockfd = dup(Sockfd);
FILE* writeFile = fdopen(Sockfd, "w");
FILE* readFile = fdopen(dupSockfd, "r");
setlinebuf(writeFile);
char writerBuff[256];
for(;;)
{
cout << "ftp> ";
if(fgets(userI, sizeof(userI), stdin))
{
if(userI == "exit")
{
return 1;
}
else
{
string cmd, f1, f2;
istringstream iss(userI, istringstream::in);
iss >> cmd >> f1 >> f2;
cout << cmd << "." << f1 << "." << f2 << endl;
if(cmd == "get")
{
write(Sockfd, "get", sizeof("get"));
Copy(f1, f2);
}
}
}
}
close(Sockfd);
}
else
{
cout << "Incorrect commands for running... try './client (hostname) (port)'" << endl;
return 1;//
}
return 0;//
}
void Copy(char *filename1,char *filename2) {
const int BUFSIZE=2048;
char buffer[BUFSIZE];
ifstream fin;
ofstream fout;
long filelen, bytesRemaining, bytes;
// Open the file to be transferred, check it exists.
fin.open( filename1);
if (!fin.good())
{
cerr << "Problems opening \"" << filename1 << "\" (" << errno << "): " << strerror(errno) << endl;
exit(1);
}
fout.open(filename2);
if (!fout.good())
{
cerr << "Problems opening \"" << filename2 << "\" (" << errno << "): " << strerror(errno) << endl;
exit(1);
}
// Determine the file's length.
fin.seekg(0,ios::end);
if(fin.fail()) cerr<<"seekg() fail!\n";
filelen = fin.tellg();
if(fin.fail()) cerr<<"tellg() fail!\n";
fin.seekg(0, ios::beg);
if(fin.fail()) cerr<<"seekg() fail!\n";
// Copy the file data.
bytesRemaining = filelen;
while (bytesRemaining > 0)
{
bytes = bytesRemaining > BUFSIZE ? BUFSIZE : bytesRemaining;
fin.read(buffer,bytes);
if(fin.fail()){
cerr<<"read() error\n";
exit(1);
}
fout.write(buffer,bytes);
if(fout.fail()){
cerr<<"write() error\n";
exit(1);
}
bytesRemaining -= bytes;
}
fin.close();
fout.close();
}
Server file
int main(int argc, char **argv)
{
if(argc == 2)
{
int Sockfd, NewSockfd, ClntLen;
sockaddr_in ClntAddr, ServAddr;
int Port = atoi(argv[1]);
char String[MAX_SIZE];
int Len;
// open a TCP socket (an Internet stream socket)
Sockfd = Socket(AF_INET, SOCK_STREAM, 0); // socket() wrapper fn
// bind the local address, so that the client can send to server
memset((char*)&ServAddr, 0, sizeof(ServAddr));
ServAddr.sin_family = AF_INET;
ServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
ServAddr.sin_port = htons(Port);
int opt = 1;
setsockopt(Sockfd,SOL_SOCKET,SO_REUSEADDR, (void*)opt, sizeof(opt));
Bind(Sockfd, (sockaddr*) &ServAddr, sizeof(ServAddr));
// listen to the socket
Listen(Sockfd, 5);
int RecvMsgSize;
for(;;)
{
// wait for a connection from a client; this is an iterative server
ClntLen = sizeof(ClntAddr);
NewSockfd = Accept(Sockfd, (sockaddr*)&ClntAddr, &ClntLen);
if((RecvMsgSize = recv(ClntSocket, EchoBuffer, RCVBUFSIZE, 0)) < 0)
{
perror("recv() failed");
exit(1);
}
// read a message from the client
Len = read(NewSockfd, String, MAX_SIZE);
String[Len] = 0;// make sure it's a proper string
cout<< String << endl;
close(NewSockfd);
}
}
else
{
cout << "Incorrect commands for running... try './server (port)'" << endl;
return 1;//
}
return 0;//
}

You want to create a Web server that will process GET and PUT requests? You first need to read how the http works. Let me explain in simple terms.
Try to develop your server first and connect it to a browser :
1.Make your server listen on port 80 - this is a must
2.Create a buffer that will read the request from the browser(client), as you do in this part of your code:
if((RecvMsgSize = recv(ClntSocket, EchoBuffer, RCVBUFSIZE, 0)) < 0)
{
perror("recv() failed");
exit(1);
}
// read a message from the client
Len = read(NewSockfd, String, MAX_SIZE);
String[Len] = 0;// make sure it's a proper string
cout<< String << endl;
close(NewSockfd);
so this String object is your buffer, it will contain the http request.
3.You need to parse the request. Parse the request to see whether the method is GET PUT POST or etc.
This is a sample GET request :
https://marketing.adobe.com/developer/documentation/data-insertion/r-sample-http-get
4.Then you need to send the proper response back to the client in this case the browser:
http://pastebin.com/BPnVHym5
5.Connect your browser to the server by typing your ip adress in the addressbar

I would honestly use a C++ REST API library to do the work. You can find one called "Casablanca."
Here's an example on how to use it for making a client: https://casablanca.codeplex.com/wikipage?title=Http%20Client%20Tutorial
Here is an example on how to create a server: https://casablanca.codeplex.com/wikipage?title=HTTP%20Listener&referringTitle=Documentation
Maybe this will get you started.

Related

C++ chat system

I am able to make client and server connect, but not chat with each other. I can only make the server receive messages and the client can only to send them...but it doesn't work the other way around.
Relevant server code:
while(recv(acceptedSocket,buffer,255,0)){
std::cout << buffer << std::endl;
memset(buffer,0,sizeof(buffer));
n = send(acceptedSocket,"Message received!", 18 , 0);
if(n < 0)
error("Failed sending data!");
}
Relevant client code:
do{
memset(buffer,0,sizeof(buffer));
std::cout << "Enter your message: " << std::endl;
std::cin.getline(buffer,255);
n = send(connectingSocket,buffer,strlen(buffer),0);
} while(n > 0);
Can I make server and client send and receive messages without multi-threading or do I have to multi-thread?
All code
Server:
int main() {
int listeningSocket,acceptedSocket,port,n;
unsigned int clientLength;
char buffer[256];
struct sockaddr_in server_address , client_address;
std::cout << "ENTER PORT(ABOVE 2000):";
std::cin >> port;
if(port < 2000){
error("NO PORT PROVIDED");
}
listeningSocket = socket(AF_INET,SOCK_STREAM,0);
if(listeningSocket < 0)
error("FAILED CREATING A SOCKET!");
memset((char * ) &server_address,0,sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(port);
if(bind(listeningSocket,(struct sockaddr *) &server_address,sizeof(server_address)) < 0)
error("BINDING FAILED!");
listen(listeningSocket,5);
clientLength = sizeof(client_address);
acceptedSocket = accept(listeningSocket,(struct sockaddr *) &client_address,&clientLength);
if(acceptedSocket < 0)
error("ACCEPTING FAILED!");
std::cout << "Connection incoming from " << client_address.sin_addr.s_addr << std::endl;
while(recv(acceptedSocket,buffer,255,0)){
std::cout << buffer << std::endl;
memset(buffer,0,sizeof(buffer));
n = send(acceptedSocket,"Message received!", 18 , 0);
if(n < 0)
error("Failed sending data!");
}
}
Client:
int main() {
int connectingSocket,portNo,n;
struct sockaddr_in server_address;
struct hostent *server;
char buffer[256];
std::cout << "Enter server's IP:";
char * ipHolder;
std::cin >> ipHolder;
server = gethostbyname(ipHolder);
if(server == NULL){
error("NO SUCH HOST!");
}
std::cout << "ENTER PORT:";
std::cin >> portNo;
connectingSocket = socket(AF_INET,SOCK_STREAM,0);
if(connectingSocket < 0)
error("FAILED OPENING A SOCKET!");
memset(&server_address,0,sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(portNo);
memcpy(server->h_addr_list,&server_address.sin_addr.s_addr,server->h_length);
if(connect(connectingSocket,(sockaddr *)&server_address,sizeof(server_address)) < 0)
error("CONNECTION FAILURE!");
std::cout << "CONNECTION MADE!" << std::endl;
std::cin.ignore();
do{
memset(buffer,0,sizeof(buffer));
std::cout << "Enter your message: " << std::endl;
std::cin.getline(buffer,255);
n = send(connectingSocket,buffer,strlen(buffer),0);
}while(n > 0);
return 0;
}
Thank you!
The easiest most straight-forward solution is making the server/client send a message and right after that make it wait for a reply from the other, like that:
server:
while(recv(acceptedSocket,buffer,255,0)){ //here you read a message
std::cout << "clients message: " << buffer << std::endl; //print it on screen
memset(buffer,0,sizeof(buffer));
/*
instead of sending "message recieved" to server, try to get
some message from the user using cin maybe
and send() what the user has entered
then loop over and get another message
*/
std::cin.getline(buffer,255); //get user's message
//don't forget to find out buffer length
n = send(acceptedSocket, buffer, buffer_len , 0); //send the message
if(n < 0)
error("Failed sending data!");
//client has got the message now, you loop and wait for his reply
}
client:
do{
memset(buffer,0,sizeof(buffer));
std::cout << "Enter your message: " << std::endl;
std::cin.getline(buffer,255); //get message
n = send(connectingSocket,buffer,strlen(buffer),0); //send it to server
/*
recv() from the connecting socket and print the message
when you loop over, the server has your message, user enters
another one, and the client waits for the message, and then
sends something the user entered
*/
recv(connectingSocket,buffer,255,0); //wait for server's user reply
std::cout << "server's message: " << buffer << std::endl;
//you have now recieved server's message, you loop over and you're ready to send his another one
} while(n > 0);
So like this, you have to wait for a reply, you cannot send 2(+) messages i a row.
I have not tested this, but it's a rough idea of what it might look like :)
I did two different programs and it works on same computer or different ones on the network...
Have fun... this is what I started with... looking at yours, there are a number of concerns... so cut and past and play with this server and client.
//Echo Server and Client using Berkley Socket Primitives
// Server
#include <sys/socket.h>
#include <netinet/in.h>
int main (int argc, const char * argv[]) {
char buffer[128];
int sinlen;
struct sockaddr_in sin;
int s, h;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(888); // Port 888
// SOCK_STREAM is TCP
s = socket(AF_INET, SOCK_STREAM,0);
// Bind socket to local port
bind(s,(struct sockaddr*)&sin,sizeof(sin));
// Listen for 1 connection
listen(s,1);
sinlen = sizeof(sin);
// 1. Block for connection
h=accept(s,(struct sockaddr*)&sin,&sinlen );
// 2. Block for receive
recv(h,buffer,sizeof(buffer),0);
// 3. Echo received data
send(h,buffer,strlen(buffer),0);
close(h);
return 0;
}
// Client
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int main (int argc, const char * argv[]) {
char buffer[128]= "Hello world";
struct sockaddr_in sin;
struct hostent *host;
int s;
host = gethostbyname("localhost");
memcpy(&(sin.sin_addr), host->h_addr,host->h_length);
sin.sin_family = host->h_addrtype;
sin.sin_port = htons(888);
// Create socket port 888
s = socket(AF_INET, SOCK_STREAM,0);
// 1. Block for server accept
connect(s, (struct sockaddr*)&sin,sizeof(sin));
// 2. Send "Hello world"
send(s,buffer,strlen(buffer)+1,0);
// 3. Block for receive
recv(s,buffer,sizeof(buffer),0);
// Print received data
NSLog(#"Received %s\n",buffer);
close(s);
return 0;
}

Why receiving data from server has a segmentation fault error (No error in sending)?

This error has destroyed my day. This is my second client server program. Server is iterative type. The functionality is 1.server is running all the time.
2.Client send a file name to server.
3.Server opens the file and process on its data and send information back to client.
But in the point that client receive data it produce a segmentation error. Even it can read inside the packet, but only "filename".
In fact server is opening a file and open linux dictionary file. It searches for any spelling problem etc. Finally it has line number, word and suggested word.
I have checked inside the list in server side and list has no error.
here is an abstract of my code. I appreciate if anyone can find the bug. I copy paste all code except processing on the file. Apologist in advance for long code.
Client side:
#include <pthread.h>
#include <regex.h>
#include "wrappers.h"
struct SType{
int Num;
char Word[20];
char sugg[20];
};
struct DataPktType
{
list<SType> MyList;
char filename[MAX_SIZE], message[MAX_SIZE];
int numslaves;
};
int main(int argc, char **argv){
int Sockfd;
sockaddr_in ServAddr;
char ServHost[] = "localhost";
hostent *HostPtr;
int Port = SERV_TCP_PORT;
DataPktType DataPkt;
DataPktType recDataPkt;
string filename, tempstr;
if (argc == 5){
strcpy(ServHost, argv[1]);
Port = atoi(argv[2]);
filename = string(argv[3]);
cout<<"filename= "<<filename<<endl;
DataPkt.numslaves = atoi(argv[4]);
} else{
cout << "Usage: \"client <server address> <port> <textfile> <numThreads>\".\n" << endl;
exit(1);
}
// Get the address of the host
HostPtr = Gethostbyname(ServHost);
if(HostPtr->h_addrtype != AF_INET)
{
perror("Unknown address type!");
exit(1);
}
memset((char *) &ServAddr, 0, sizeof(ServAddr));
ServAddr.sin_family = AF_INET;
ServAddr.sin_addr.s_addr = ((in_addr*)HostPtr->h_addr_list[0])->s_addr;
ServAddr.sin_port = htons(Port);
// Open a TCP socket
Sockfd = Socket(AF_INET, SOCK_STREAM, 0);
// Connect to the server
Connect(Sockfd, (sockaddr*)&ServAddr, sizeof(ServAddr));
strcpy(DataPkt.filename, argv[3]);
DataPkt.numslaves = 6;
// Write and read a message to/from the server
write(Sockfd, (char*)&DataPkt, sizeof(DataPktType));
read(Sockfd, (char*)&recDataPkt, sizeof(DataPktType));
cout<<"here"<<endl;
cout << setw(30) << left << "Filename:" << setw(20) << right << DataPkt.filename << endl;
list<SType> MyList2;
MyList2 = DataPkt.MyList;
cout<<"size= "<<MyList2.size()<<endl;
for (list<SType>::iterator it=MyList2.begin(); it!=MyList2.end(); it++)
cout << ' ' << it->Num << ' ' << it->Word << endl;
cout << "Finished\n";
close(Sockfd);
return 0;
}
Server side:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fstream.h>
#include <list>
#include <iomanip>
#include <pthread.h>
#include "wrappers.h"
#include<cstdlib>
#include<fstream>
#include<iostream>
#include<sstream>
#include <algorithm>
#define BUFSIZE 10
#define gNumThreads 6
using namespace std;
struct SType{
int Num;
char Word[20];
char sugg[20];
};
struct DataPktType
{
list<SType> MyList;
char filename[MAX_SIZE], message[MAX_SIZE];
int numslaves;
};
int main(int argc, char **argv){
int Sockfd, NewSockfd, ClntLen, Port = SERV_TCP_PORT;
sockaddr_in ClntAddr, ServAddr;
DataPktType DataPkt;
if (argc == 2){
Port = atoi(argv[1]);
}
// Open a TCP socket (an Internet stream socket)
Sockfd = Socket(AF_INET, SOCK_STREAM, 0); // socket() wrapper fn
// Setup server for development
setsockopt(Sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
// Bind the local address, so that the client can send to server
memset((char*)&ServAddr, 0, sizeof(ServAddr));
ServAddr.sin_family = AF_INET;
ServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
ServAddr.sin_port = htons(Port);
Bind(Sockfd, (sockaddr*) &ServAddr, sizeof(ServAddr));
// Listen to the socket
Listen(Sockfd, 5);
for(;;)
{
// Wait for a connection from a client; this is an iterative server
ClntLen = sizeof(ClntAddr);
NewSockfd = Accept(Sockfd, (sockaddr*)&ClntAddr, &ClntLen);
if(NewSockfd < 0)
{
perror("Can't bind to local address!");
}
// Read a message from the client
read(NewSockfd, (char*)&DataPkt, sizeof(DataPktType));
string line;
ifstream myfile (DataPkt.filename);
if (myfile.is_open())
{
--Here is some operation I deleted to make file shorter ---
if(!found)
{
/* Add suggestion to the list */
SType S;
S.Num = lineNo;
strcpy(S.Word, result);
strcpy(S.sugg, sugg);
MyList2.push_back(S);
cout<<lineNo<<" "<<result<<" "<<sugg<<endl;
cout<<"Not found in dictionary"<<endl;
}
else
{
cout<<"found: "<<result<<" in dictionary"<<endl;
}
}
}
myfile.close();
cout<<"List before write"<<endl;
for (list<SType>::iterator it=MyList2.begin(); it!=MyList2.end(); it++)
cout << ' ' << it->Num << ' ' << it->Word << endl;
/*Send suggestion back to the client*/
DataPktType retPack;
retPack.MyList = MyList2;
//DataPkt.filename
strcpy(retPack.filename,"behzad");
write(NewSockfd, (char*)&retPack, sizeof(DataPktType));
}
else {cout << "Unable to open file"; exit(1);}
}
close(NewSockfd);
/* exit the program */
return(0);
}
output:
serverside:
1 bernard behead
Not found in dictionary
List before write
lineNo: 1 word: behzad sugg: behead
clientside:
$ ./client localhost 19431 carol.txt 6
filename= carol.txt
Finished
Segmentation Fault
You are not doing any kind of serialization over your data before send or receive.
write(Sockfd, (char*)&DataPkt, sizeof(DataPktType));
read(Sockfd, (char*)&recDataPkt, sizeof(DataPktType));
That part is completely wrong, you have a std::list into your struct, you need first to process that data before send it.

Can't receive data from network using udp protocol

My aim is to write C++ program which receives data from network using udp protocol. OS - linux. I have few questions.
I want to make sure that I can use linux C libraries to write C++ program.
Is anywhere exists full tutorial which expailns step by step how to program using sockets in linux? ( I know that in network is many tutorials, but I'm looking for something which help me receive udp data from INTERNET, not from another program on the same device.).
I see in terminal ( using tcpdump) that my computer receive udp packages addressed to specified port. What's wrong with my program which looks like this
class Connection
{
private:
char * buffer;
int bufferSize;
int sock;
struct sockaddr_in server;
struct sockaddr_in other;
socklen_t addressLength;
public:
Connection(string address, int port, int bufferSize);
~Connection();
int reciveData();
};
Connection::Connection(string address, int port, int bufferSize)
{
this->addressLength = sizeof(this->server);
this->sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(this->sock == -1)
{
cout << "Socket error!" << endl;
exit(1);
}
memset(&(this->server), 0, sizeof(this->server));
this->server.sin_family = AF_INET;
this->server.sin_port = htons(port);
this->server.sin_addr.s_addr = htonl(INADDR_ANY);
if( bind(this->sock, (sockaddr *) &(this->server), this->addressLength) == -1 )
{
cout << "Bind socket error!" << endl;
exit(1);
}
this->bufferSize = bufferSize;
this->buffer = new char[bufferSize];
cout << "Socket created!" << endl;
}
int Connection::receiveData()
{
int returned;
fflush(stdout);
if( (returned =recvfrom(this->sock, this->buffer, this->bufferSize, 0, (sockaddr *) &(this->other), &this->addressLength)) == -1)
{
cout << "Receiving error!" << endl;
exit(1);
}
return returned;
}
When i call receiveData() nothing's happening - I think program waits for some udp package ( and i don't know why he does not receive it).
Could someone explain me difference between udp server and client program ?
Thanks a lot.
When calling recvfrom(), you are passing it a pointer to this->addressLength. On input, the length needs to be the complete size of the address buffer. On output, the actual address length is returned. So recvfrom() might be altering your addressLength member, affecting subsequent code. Use a local variable instead:
int Connection::receiveData()
{
int returned;
int addrlen = sizeof(this->other);
fflush(stdout);
returned = recvfrom(this->sock, this->buffer, this->bufferSize, 0, (sockaddr *) &(this->other), &addrLen);
if( returned == -1 )
{
cout << "Receiving error!" << endl;
exit(1);
}
return returned;
}
Alternatively, use a separate member variable instead:
class Connection
{
private:
char * buffer;
int bufferSize;
int sock;
struct sockaddr_in server;
struct sockaddr_in other;
socklen_t serverAddressLength;
socklen_t otherAddressLength;
public:
Connection(string address, int port, int bufferSize);
~Connection();
int reciveData();
};
Connection::Connection(string address, int port, int bufferSize)
{
this->serverAddressLength = sizeof(this->server);
this->sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(this->sock == -1)
{
cout << "Socket error!" << endl;
exit(1);
}
if(this->sock == -1)
{
cout << "Socket error!" << endl;
exit(1);
}
memset(&(this->server), 0, sizeof(this->server));
this->server.sin_family = AF_INET;
this->server.sin_port = htons(port);
this->server.sin_addr.s_addr = htonl(INADDR_ANY);
if( bind(this->sock, (sockaddr *) &(this->server), this->serverAddressLength) == -1 )
{
cout << "Bind socket error!" << endl;
exit(1);
}
this->bufferSize = bufferSize;
this->buffer = new char[bufferSize];
cout << "Socket created!" << endl;
}
int Connection::receiveData()
{
int returned;
fflush(stdout);
this->otherAddressLength = sizeof(this->other);
if( (returned =recvfrom(this->sock, this->buffer, this->bufferSize, 0, (sockaddr *) &(this->other), &this->otherAddressLength)) == -1)
{
cout << "Receiving error!" << endl;
exit(1);
}
return returned;
}

C++ strange socket data

Hey guys, here is my code.
int main() {
char buffer[BUFSIZE];
// define our address structure, stores our port
// and our ip address, and the socket type, etc..
struct sockaddr_in addrinfo;
addrinfo.sin_family = AF_INET;
addrinfo.sin_port = htons(PORT);
addrinfo.sin_addr.s_addr = INADDR_ANY;
// create our socket.
int sock;
if ( (sock = socket(addrinfo.sin_family, SOCK_STREAM, 0)) < 0) {
cout << "Error in creating the socket.";
}
// bind our socket to the actual adress we want
if (bind(sock, (struct sockaddr*)&addrinfo, sizeof(addrinfo)) != 0) {
cout << "Error in binding.";
}
// open the socket up for listening
if (listen(sock, 5) != 0) {
cout << "Error in opening listener.";
}
cout << "Waiting for connections...." << endl;
char *msg = "Success! You are connected.\r\n";
// continuously accept new connections.. but no multithreading.. yet
while(1) {
struct sockaddr_in client_addr;
socklen_t sin_size = sizeof(client_addr);
if(int client = accept(sock, (struct sockaddr*)&client_addr, &sin_size)) {
cout << "Recived new connection from " << inet_ntoa(client_addr.sin_addr) << endl;
send(client, msg, strlen(msg), 0);
while(1) {
send(client, buffer, recv(client, buffer, BUFSIZE, 0), 0);
cout << buffer << endl;
strcpy(buffer, "");
}
} else {
cout << "Error in accepting new connection." << endl;
}
}
close(sock);
return 0;
}
Now, I'm very new to sockets, Im just sort of trying to get a feel for them but I do have some experience with sockets in PHP. I'm using telnet via putty on my linux machine to test this, I don't know if thats causing any issues but the server is outputting some strange characters and I don't know why. I think it has something to do with the buffer, but I'm not really sure. I can send things like "hi" to the server via telnet and it outputs them just fine and sends them back to me but when I send things like "hoobla" it starts the funky character stuff. Any suggestions would be helpful!
Thanks in advance!
You're getting rubbish printed out because recv does not null-terminate your buffer.
The important section in the below code is:
int num = recv(client,buffer,BUFSIZE,0);
if (num < 1) break;
send(client, ">> ", 3, 0); // <<-- Nice to have.
send(client, buffer, num, 0);
buffer[num] = '\0'; // <<-- Really important bit!
if (buffer[num-1] == '\n') // <<-- Nice to have.
buffer[num-1] = '\0'; // <<-- Nice to have.
cout << buffer << endl;
which will properly terminate your buffer before trying to print it, as well as remove the trailing newline if present (and allow the client to distinguish between input and echoed lines).
This one (a complete program) works a little better:
using namespace std;
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#define BUFSIZE 1000
#define PORT 1234
int main() {
char buffer[BUFSIZE];
// define our address structure, stores our port
// and our ip address, and the socket type, etc..
struct sockaddr_in addrinfo;
addrinfo.sin_family = AF_INET;
addrinfo.sin_port = htons(PORT);
addrinfo.sin_addr.s_addr = INADDR_ANY;
// create our socket.
int sock;
if ( (sock = socket(addrinfo.sin_family, SOCK_STREAM, 0)) < 0) {
cout << "Error in creating the socket.";
return -1;
}
// bind our socket to the actual adress we want
if (bind(sock, (struct sockaddr*)&addrinfo, sizeof(addrinfo)) != 0) {
cout << "Error in binding.";
return -1;
}
// open the socket up for listening
if (listen(sock, 5) != 0) {
cout << "Error in opening listener.";
return -1;
}
char *msg = "Success! You are connected.\r\n";
// continuously accept new connections.. but no multithreading.. yet
while(1) {
cout << "Waiting for connections...." << endl;
struct sockaddr_in client_addr;
socklen_t sin_size = sizeof(client_addr);
if(int client =
accept(sock, (struct sockaddr*)&client_addr, &sin_size))
{
cout << "Recieved new connection from "
<< inet_ntoa(client_addr.sin_addr) << endl;
send(client, msg, strlen(msg), 0);
while(1) {
int num = recv(client,buffer,BUFSIZE,0);
if (num < 1) break;
send(client, ">> ", 3, 0);
send(client, buffer, num, 0);
buffer[num] = '\0';
if (buffer[num-1] == '\n')
buffer[num-1] = '\0';
cout << buffer << endl;
strcpy(buffer, "");
}
} else {
cout << "Error in accepting new connection." << endl;
}
}
close(sock);
return 0;
}
On the client side:
$ telnet 127.0.0.1 1234
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Success! You are connected.
hello
>> hello
my name is pax
>> my name is pax
and you?
>> and you?
<CTRL-D>
Connection closed by foreign host.
and, on the server side:
$ ./testprog
Waiting for connections....
Recived new connection from 127.0.0.1
hello
my name is pax
and you?
Waiting for connections....
The problem is that buffer is not guaranteed to contain a string-terminating null character. Add the line buffer[BUFSIZE-1] = '\0' just before your cout << buffer.
Even better, actually record how many bytes were received, and use that information to determine if you overran your buffer.

extra newlines at end of file transported over tcp

I have two programs, recvfile.py and sendfile.cpp. They work except that I end up with a bunch of extra newline characters at the end of the new file. I don't know how the extra spaces get there. I know the problem is sender side, because the same doesn't happen when I use python's sendall() function to send the file.
Here are the files:
jmm_sockets.c
#include <winsock.h>
#include <stdio.h>
#include <stdlib.h>
int getServerSocket(int port)
{
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,0), &wsaData) != 0){
fprintf(stderr, "WSAStartup() failed\n");
exit(1);
}
// create socket for incoming connections
int servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(servSock == INVALID_SOCKET){
fprintf(stderr, "Oops: socket() failed %d\n", WSAGetLastError());
exit(1);
}
// construct local address structure
struct sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = INADDR_ANY;
servAddr.sin_port = htons(port);
// bind to the local address
int servAddrLen = sizeof(servAddr);
if(bind(servSock, (SOCKADDR*)&servAddr, servAddrLen) == SOCKET_ERROR){
fprintf(stderr, "Oops: bind() failed %d\n", WSAGetLastError());
exit(1);
}
return servSock;
}
int getClientSocket(char* host, int port)
{
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,0), &wsaData) != 0){
fprintf(stderr, "Oops: WSAStartup() failed");
exit(1);
}
// create tcp socket
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(socket<0){
fprintf(stderr, "Oops: socket() failed %d\n", WSAGetLastError());
exit(1);
}
// set up serverAddr structure
struct sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr(host);
servAddr.sin_port = htons(port);
// connecet to server address
if(connect(sock, (SOCKADDR*)&servAddr, sizeof(servAddr)) < 0){
fprintf(stderr, "Oops: connect() failed. %d\n", WSAGetLastError());
exit(1);
}
return sock;
}
sendfile.cpp:
#include "jmm_sockets.h"
#include <windows.h>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <sys/stat.h>
using namespace std;
int main(int argc, char** argv)
{
int port;
string host;
string filename;
if(argc==2){
cout << "Host: ";
cin >> host;
cout << "Port: ";
cin >> port;
filename = argv[1];
}else if (argc == 4){
host = argv[1];
port = atoi(argv[2]);
filename = argv[3];
}else{
cerr << "Usage: " << argv[0] << " [<host> <port>] <filename>" << endl;
exit(1);
}
// open file for reading
ifstream fin;
fin.open(filename.c_str());
if(fin.fail()){
cerr << "Error: opening " << filename << " failed. " << endl;
exit(1);
}
// get file size
fin.seekg(0, ios::end);
int size = fin.tellg();
fin.seekg(0, ios::beg);
// open socket for sending
int sock = getClientSocket((char*)host.c_str(), port);
// send file size
char buffer[16];
itoa(size, buffer, 10);
int i;
for(i=0; i<strlen(buffer); i++){
if(send(sock, &buffer[i], 1, 0)!=1){
cerr << "Error: send() failed " << WSAGetLastError() << endl;
exit(1);
}
}
char c = '\n';
if(send(sock, &c, 1, 0)!=1){
fprintf(stderr, "Error: send() failed %d\n", WSAGetLastError());
exit(1);
}
// recv y or n
int recvMsgSize = recv(sock, &c, 1, 0);
if(recvMsgSize!=1){
fprintf(stderr, "Error: recv() failed %d\n", WSAGetLastError());
exit(1);
}
if(c=='y'){
// send entire file
int readSoFar = 0;
while(readSoFar < size){
fin.get(c);
if(send(sock, &c, 1, 0)!=1){
cerr << "Error: send() failed " << WSAGetLastError() << endl;
exit(1);
}
readSoFar++;
}
}else if (c=='n'){
// leave
cout << "Remote host declined file." << endl;
}
fin.close();
closesocket(sock);
WSACleanup();
//
return 0;
}
and finally, recvfile.py:
import sys
from jmm_sockets import *
import yesno
if len(sys.argv) != 2:
print "Usage: ", argv[0], "<port>"
s = getServerSocket(None, int(sys.argv[1]))
conn, addr = s.accept()
buffer = None
filelen = str()
# receive filesize
while 1:
buffer = conn.recv(1)
if buffer == '\n':
# give it a rest
break
else:
filelen = filelen + buffer
# prompt user to accept file
filelen = int(filelen)
print "file size = ", filelen,
userChoice = yesno.yesno("Accept?")
conn.send(userChoice)
# conditionally accecpt file
if bool(userChoice):
filename = raw_input("What do you want to call the file? ")
f = open(filename, 'w')
buffer = None
data = str()
recvdBytes = 0
while recvdBytes < filelen:
buffer = conn.recv(1)
recvdBytes = recvdBytes + 1
data = data + buffer
print "File: ",
f.write(data)
print "written"
conn.close()
The reason you're ending up with extra newlines is because you're sending extra newlines across the socket, which is because you try to send more data than you should.
If you checked the fail() state of your input file fin, you'd discover that it's failing on the last several calls to fin.get(c), so the value of c remains unchanged -- it stays as a newline character, which is the last character in the input file.
This is happening because of CRLF translation: the file size you're using (the size variable) is the raw file size on disk, counting all of the CRs. But, when you open it up in text mode and read it in one byte at a time, the standard library silently translates all CRLFs into LFs, so you don't send the CRs across the socket. Hence, the number of extra newlines you get at the end of this process is equal to the number of newlines that were in the original file.
The way to fix this is to open the file in binary mode to disable CRLF translation:
fin.open(filename.c_str(), ios::in | ios::binary);
Furthermore, you shouldn't be sending the file one byte at a time -- this is horrendously slow. If you're unlucky, you'll be sending an entire packet for each byte. If you're lucky, your OS's network stack will accumulate these multiple sends into larger packets (don't depend on that), but even then you're still making a huge number of system calls into the kernel.
Consider refactoring your code to make fewer calls to send() and recv(), where you pass a larger number of bytes per call, e.g.:
// Just use one call to send instead of looping over bytes and sending one
// byte at a time. Simpler and faster!
send(sock, buffer, strlen(buffer), 0);