I am writing a tftp server in C and testing it with the tftp command on the terminal. However, for most of the times, I receive something liske the following when I try to send RRQ:
tftp> get a.txt
sent RRQ <file=a.txt, mode=netascii>
received ERROR <code=4, msg=>
Error code 1024:
other barly happend case includes:
tftp> get a.txt
sent RRQ <file=a.txt, mode=netascii>
received DATA <block=20334, 512 bytes>
discarded 4 packets
and this one: this might look correct but it barely happened. The text file I use to test it is of 857 bytes.
sent ACK <block=1>
received DATA <block=1, 512 bytes>
sent ACK <block=1>
received DATA <block=2, 345 bytes>
Received 857 bytes in 0.0 seconds
and here is part of my code
Here buffer is a char array of size 512 , to simplify the code, I have removed some of the error handling code
Thanks to whoever may help
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <cerrno>
//define opcode for later use
enum opcode {
RRQ = 1,
WRQ,
DATA,
ACK,
ERROR
};
void handle_write(struct sockaddr_in * sock_info, char* filename, int BUF_LEN){
//printf("Received write request + %d\n", WRQ);
return;
}
void handle_error(unsigned short int * opcode_ptr, char* buffer, socklen_t sockaddr_len, int server_socket, struct sockaddr_in * sock_info, const char* errormsg){
ssize_t n;
*opcode_ptr = htons(ERROR);
*(opcode_ptr + 1) = htons(1);
*(buffer + 4) = 0;
//memcpy(buffer+4, errormsg, strlen(errormsg));
intr_send:
n = sendto(server_socket, buffer, 5, 0,
(struct sockaddr *)sock_info, sockaddr_len);
if(n < 0) {
if(errno == EINTR) goto intr_send;
perror(errormsg);
exit(-1);
}
return;
}
int main() {
int BUF_LEN = 516;
ssize_t n;
char buffer[BUF_LEN];
socklen_t sockaddr_len;
int server_socket;
struct sigaction act;
unsigned short int opcode;
unsigned short int * opcode_ptr;
struct sockaddr_in sock_info;
memset(&sock_info, 0, sockaddr_len);
//----------setup the server----------------//
sock_info.sin_addr.s_addr = htonl(INADDR_ANY);
sock_info.sin_port = htons(5743);
sock_info.sin_family = PF_INET;
if((server_socket = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(-1);
}
sockaddr_len = sizeof(sock_info);
if(bind(server_socket, (struct sockaddr *)&sock_info, sockaddr_len) < 0) {
perror("bind");
exit(-1);
}
getsockname(server_socket, (struct sockaddr *)&sock_info, &sockaddr_len);
printf("UDP server listening on port: %d\n", ntohs(sock_info.sin_port));
//----------setup the server----------------//
while(1){
intr_recv:
n = recvfrom(server_socket, buffer, BUF_LEN, 0, (struct sockaddr *)&sock_info, &sockaddr_len);
if(n < 0) {
if(errno == EINTR) goto intr_recv;
perror("recvfrom()");
exit(-1);
}
opcode_ptr = (unsigned short int *)buffer;
opcode = ntohs(*opcode_ptr); //the opcode will be either RRQ or WRQ according to the test
if(opcode != RRQ && opcode != WRQ) {
/* Illegal TFTP Operation */
handle_error(opcode_ptr, buffer, sockaddr_len, server_socket, &sock_info, "invalid command");
}
else {
if(fork() == 0) {
/* Child - handle the request */
FILE* fd;
char* filename;
filename = strdup(buffer+2); //this is the filename to be read (i.e. a.txt)
printf("request received\n");
char data[512];
//----------------------------------handle read request-------------------------------------//
if(opcode == RRQ){
int blocknumber = 0;
int i = 0; //counter for loop
fd = fopen(filename, "r");
free(filename);
//uint8_t data[512];
ssize_t datalen, n;
int done = 0; //this is a boolean indicator that indicates whether the packet transfering process is done or not.
while(!done){
datalen = fread(data, 1, 512, fd);
blocknumber++;
if(datalen < 512){
done = 1; //according to rfc 1350, the last packet will have a data length less than 512 bytes.
}
//for(i = 5; i > 0; i--){
*opcode_ptr = htons(DATA);
opcode = ntohs(*opcode_ptr);
*(opcode_ptr + 1) = htons(blocknumber);
memcpy(buffer + 4, data, datalen);
buffer[datalen + 4] = '\0';
//*(buffer + 4) = 0;
//printf("%d %s\n", datalen, buffer+2);
n = sendto(server_socket, buffer, 4 + datalen, 0, (struct sockaddr *)&sock_info, sockaddr_len);
if(n < 0){
perror("sendto() failed");
exit(-1);
}
//printf("done %d\n", done);
//char buffer[512];
n = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr *)&sock_info, &sockaddr_len);
opcode_ptr = (unsigned short int *)buffer;
opcode = ntohs(*opcode_ptr);
if(n >= 0 && n < 4){
//handle_error(opcode_ptr, buffer, sockaddr_len, server_socket, &sock_info, "invalid request size");
}
if(n > 4){
break;
}
//}
//if(i != 0){
// printf("Transfer timeout!\n");
// exit(1);
//}
//printf("opcode is %d\n", opcode);
if(opcode == ERROR){
printf("Error received\n");
exit(1);
}
if(opcode != ACK){
printf("Invalid message received\n");
exit(1);
}
}
}
//----------------------------------handle read request-------------------------------------//
//----------------------------------handle write request------------------------------------//
//----------------------------------handle write request------------------------------------//
close(server_socket);
break;
}
else {
/* Parent - continue to wait */
}
}
}
return EXIT_SUCCESS;
}
I read your code but not tested by executing.
Compareing with RFC 1350, what I found are
The data field is upto 512 bytes, so 512-byte buffer is not enough because there are no room for the header (Opcode and Block #). You need at least 4 more bytes.
You write the data from buffer + 2 via memcpy(). This should destroy the block number. It seems buffer + 4 should be used instead.
buffer[datalen + 2] = '\0'; shouldn't be needed. I think you should remove it because it will destroy the data or cause buffer overrun.
You should close the file opened after handling read request.
Related
I'm implementing a server in C++ with non-blocking sockets.
Since I want to send messages between the client & server, I wrote 2 wrappers around send/recv syscalls. Mainly, I want to prepend 4Bytes (message length) to every message, so that the receiver knows how long to execute recv.
Moreover I have a client/server programs that each start a socket and listen on localhost.
Then the client sends a random message, which the server receives.
When I try,however, to send from the server to the client, both programs halt.
I have tested the wrappers many times and they read/deliver data, but whenever I try to receive on a previously sending connection, then comes the problem.
I know that there is a memory leak in the secure_recv but I need it to pass some custom tests, which are not very well written.
The issue lies in the select, which returns a positive number, but then I never go inside the if (FD_ISSET(fd, &readset)) statement.
What am I doing wrong and how can we fix it ? Thanks a lot !
EDIT
My problem was that the sockets were blocking(busy working) at the select function. I updated the code so that there is no select in the secure_* functions. It's a much better way to first check if the socket is available for send/recv on a client/server thread level via select and then calling the secure_* functions. Question is answered for now.
client.cpp
// Client side C/C++ program to demonstrate Socket programming
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include "util.h"
#define PORT 8080
int main(int argc, char const *argv[])
{
int sock = 0, valread;
struct sockaddr_in serv_addr;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
int numbytes;
size_t size = 0;
std::unique_ptr<char[]> buf = get_rand_data(size);
if ((numbytes = secure_send(sock, buf.get(), size, 0)) == -1)
{
std::cout << std::strerror(errno) << "\n";
exit(1);
}
std::cout << "Client sent : " << numbytes << "\n";
int64_t bytecount = -1;
while (1)
{
std::unique_ptr<char[]> buffer;
if ((bytecount = secure_recv(sock, buffer, 0)) <= 0)
{
if (bytecount == 0)
{
break;
}
}
std::cout << bytecount << "\n";
}
std::cout << "Client received : " << bytecount << "\n";
close(sock);
return 0;
}
server.cpp
// Server side C/C++ program to demonstrate Socket programming
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include "util.h"
#define PORT 8080
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
// Forcefully attaching socket to the port 8080
if (bind(server_fd, (struct sockaddr *)&address,
sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
// set the socket to non-blocking mode
fcntl(new_socket, F_SETFL, O_NONBLOCK);
int64_t bytecount = -1;
while (1) {
std::unique_ptr<char[]> buffer;
if ((bytecount = secure_recv(new_socket, buffer, 0)) <= 0) {
if (bytecount == 0) {
break;
}
}
std::cout << bytecount << "\n";
}
int numbytes;
size_t size = 0;
std::unique_ptr<char[]> buf = get_rand_data(size);
if ((numbytes = secure_send(new_socket, buf.get(), size, 0)) == -1)
{
std::cout << std::strerror(errno) << "\n";
exit(1);
}
std::cout << "Client sent : " << numbytes << "\n";
close(new_socket);
return 0;
}
util.h
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <signal.h>
#include <cstring>
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <algorithm>
#include <memory>
#include <poll.h>
#include <iomanip>
/**
* It takes as arguments one char[] array of 4 or bigger size and an integer.
* It converts the integer into a byte array.
*/
void convertIntToByteArray(char *dst, int sz)
{
auto tmp = dst;
tmp[0] = (sz >> 24) & 0xFF;
tmp[1] = (sz >> 16) & 0xFF;
tmp[2] = (sz >> 8) & 0xFF;
tmp[3] = sz & 0xFF;
}
/**
* It takes as an argument a ptr to an array of size 4 or bigger and
* converts the char array into an integer.
*/
int convertByteArrayToInt(char *b)
{
return (b[0] << 24) + ((b[1] & 0xFF) << 16) + ((b[2] & 0xFF) << 8) + (b[3] & 0xFF);
}
/**
* It constructs the message to be sent.
* It takes as arguments a destination char ptr, the payload (data to be sent)
* and the payload size.
* It returns the expected message format at dst ptr;
*
* |<---msg size (4 bytes)--->|<---payload (msg size bytes)--->|
*
*
*/
void construct_message(char *dst, char *payload, size_t payload_size)
{
convertIntToByteArray(dst, payload_size);
memcpy(dst + 4, payload, payload_size);
}
/**
* It returns the actual size of msg.
* Not that msg might not contain all payload data.
* The function expects at least that the msg contains the first 4 bytes that
* indicate the actual size of the payload.
*/
int get_payload_size(char *msg, size_t bytes)
{
// TODO:
return convertByteArrayToInt(msg);
}
/**
* Sends to the connection defined by the fd, a message with a payload (data) of size len bytes.
* The fd should be non-blocking socket.
*/
/**
* Receives a message from the fd (non-blocking) and stores it in buf.
*/
int secure_recv(int fd, std::unique_ptr<char[]> &buf)
{
// TODO:
int valread = 0;
int len = 0;
int _len = 4;
bool once_received = false;
std::vector<char> ptr(4);
while (_len > 0)
{
int _valread = recv(fd, ptr.data() + valread, _len, MSG_DONTWAIT);
if (_valread == 0)
{
break;
}
if (_valread > 0)
{
_len -= _valread;
valread += _valread;
}
if (!once_received && valread == 4)
{
once_received = true;
len = convertByteArrayToInt(ptr.data());
_len = len;
ptr = std::vector<char>(len);
valread = 0;
}
}
buf = std::make_unique<char[]>(len);
memcpy(buf.get(), ptr.data(), len);
return len;
}
/**
* Sends to the connection defined by the fd, a message with a payload (data) of size len bytes.
* The fd should be non-blocking socket.
*/
int secure_send(int fd, char *data, size_t len)
{
// TODO:
char ptr[len + 4];
int valsent = 0;
int _len = 4;
bool once_sent = false;
construct_message(ptr, data, len);
while (_len > 0)
{
int _valsent = send(fd, ptr + valsent, _len, MSG_DONTWAIT);
if (_valsent == 0)
{
break;
}
if (_valsent > 0)
{
_len -= _valsent;
valsent += _valsent;
}
if (!once_sent && valsent == 4)
{
once_sent = true;
_len = len;
}
}
return len;
}
Compilation via
g++ -O3 -std=c++17 -Wall -g -I../ client.cpp -o client -lpthread
Let's start with the write loop:
while (1)
{
// std::cerr << "first iteration send\n";
FD_ZERO(&writeset);
FD_SET(fd, &writeset);
if (select(fd + 1, NULL, &writeset, NULL, NULL) > 0)
{
if (FD_ISSET(fd, &writeset))
{
valsent = send(fd, ptr + valsent, _len, 0);
Oops. This loses valsent, which tracks how many bytes you've sent so far. So on your third loop, ptr + valsent will only add the number of bytes received the second time. You need to track the total number of bytes sent so far somewhere.
if (valsent <= 0)
{
break;
}
_len -= valsent;
And what if _len becomes zero? You'll still call select and even send. You probably want that while (1) to be while (_len > 0).
}
}
}
return len;
Now, onto the read loop:
if (select(fd + 1, &readset, NULL, NULL, NULL) > 0)
{
if (FD_ISSET(fd, &readset))
{
if (first_iteration)
{
recv(fd, ptr, 4, 0);
You ignore the return value of recv here. What if it's not 4?
len = convertByteArrayToInt(ptr);
buf = std::make_unique<char[]>(len);
_len = len;
first_iteration = false;
}
valread = recv(fd, buf.get() + valread, _len, 0);
if (valread <= 0)
{
break;
}
_len -= valread;
You don't leave the loop if _len is zero. You'll call select again, waiting for data that may never come.
}
}
This is a simple client server system. Server uses select to handle different client request. But the problem is: When I shut down the client, server will get segmentation fault. I don't know how to deal with the situation.
Thanks for your help.
Client Side:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <queue>
#include <cstdlib>
#include <string.h>
#include <mutex>
#include <thread>
#include <pthread.h>
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
#include <stdlib.h> /* for atoi() and exit() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
#include <ctype.h>
#define SIZESTACKSPACE 1000000;
#define RCVBUFSIZE 32 /* Size of receive buffer */
using namespace std;
void *sendRequest(void *);
void *receiveRequest(void *);
//#define TEMPPORTNO "40868";
//#define IP1 "10.10.154.41";
//#define IP1 "192.168.37.166";
int sock; /* Socket descriptor */
bool running1 = true, running2 = true;
//queue1 is used for sending message
//queue2 is used by recieve to display message
queue<char*> queue1, queue2;
//create two mutex for two queue
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
//create conditional variables
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
pthread_attr_t attr;
int main(void){
pthread_t thread2, thread1;
int rc2, rc1;
size_t stacksize;
//initialize attributes
pthread_attr_init(&attr);
pthread_attr_getstacksize (&attr, &stacksize);
stacksize = sizeof(double)*1000+SIZESTACKSPACE;
pthread_attr_setstacksize(&attr, stacksize);
//create thread1, with function sendRequest()
rc1 = pthread_create(&thread1, &attr, sendRequest, NULL);
if(rc1){
cout<<" ERROR; return code from pthread_create() is " << rc1;
exit(-1);
}
//create thread2, with the function recieveRequest()
rc2 = pthread_create(&thread2, &attr, receiveRequest, NULL);
if(rc2){
cout<<" ERROR; return code from pthread_create() is " << rc2;
exit(-1);
}
int chunksize = 4; /* use BUFSIZ-1 for (probably) more efficient program */
char *s;
char *temp;
int buffersize;
int nPos;
char c;
char *str;
while(1){
buffersize = chunksize+1;
s = (char*) malloc(buffersize); /* get the first chunk */
if (s == NULL) {
printf("Can't allocate %d bytes\n", buffersize);
exit(1);
}
if((c=getchar()) != '\n' && c != EOF){
nPos = 1;
s[0] = c;
while((c=getchar()) != '\n' && c != EOF){
s[nPos] = c;
if(nPos>=buffersize){
buffersize += chunksize;
temp = (char*)realloc(s, buffersize);
if (temp == NULL) {
printf("Can't realloc %d bytes\n", chunksize);
free(s); /* clean up the previously allocated stuff */
s = NULL;
exit(1);
}
s=temp;
}
nPos++;
}
int k, j;
/*The last character is null*/
//nPos is the length of the string, aside of the null character
s[nPos] = '\0';
//to store the new string, allocation
str = (char*) malloc(nPos+6);
j = nPos;
//each byte contains a value of the number
k = 3;
while(k>=0){
str[k] = nPos % 10;
nPos = nPos/10;
k--;
}
str[4] = '\0';
k = 0;
while(k<=j){
str[k+5] = s[k];
k++;
}
str[k+5] = '\0';
free(s);
//add mutex here
pthread_mutex_lock(&mutex1);
queue1.push(str);
//signal sendRequest
if(!queue1.empty())
pthread_cond_signal(&cond1);
pthread_mutex_unlock(&mutex1);
//signal recvRequest
pthread_mutex_lock(&mutex2);
queue2.push(str);
if(!queue2.empty())
pthread_cond_signal(&cond2);
pthread_mutex_unlock(&mutex2);
}else if(c==EOF){
break;
}
}
//wait for thread 2
while(!queue2.empty());
//signal for threads
close(sock);
/* Clean up and exit */
pthread_attr_destroy(&attr);
pthread_exit(NULL);
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
pthread_cond_destroy(&cond1);
pthread_cond_destroy(&cond2);
return 0;
}
void *sendRequest(void *){
struct sockaddr_in echoServAddr; /* Echo server address */
unsigned short servPort; /* server port */
char* servIP; /* Server IP address (dotted quad) */
char* echoString; /* String to send to echo server */
unsigned int stringLen;
char* tempPort;
//fetch environment variables from the system
servIP = getenv ("SERVER_ADDRESS");
tempPort = getenv("SERVER_PORT");
// servIP = IP1;
// tempPort = TEMPPORTNO;
if(strlen(servIP) == 0 || strlen(tempPort) == 0){
perror("DOES NOT SET ENVIRONMENT VARIABLES FOR SERVER_ADDRESS OR SERVER_PORT\n");
exit(-1);
}
servPort = atoi(tempPort);
/* Create a reliable, stream socket using TCP */
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
printf("socket() failed\n");
exit(1);
}
/* Construct the server address structure */
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
echoServAddr.sin_family = AF_INET; /* Internet address family */
echoServAddr.sin_addr.s_addr = inet_addr(servIP); /* Server IP address */
echoServAddr.sin_port = htons(servPort); /* Server port */
/* Establish the connection to the echo server */
if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0){
perror("connect() failed\n");
exit(1);
}
pthread_mutex_lock(&mutex1);
while(true){
pthread_cond_wait(&cond1, &mutex1);
echoString = queue1.front();
queue1.pop();
pthread_mutex_unlock(&mutex2);
//send a request to the server
//determine the length that is going to be sent
stringLen = 5;
while(echoString[stringLen])
stringLen++;
/* Send the string to the server */
if (send(sock, echoString, stringLen, 0) != (int)stringLen){
perror("send() sent a different number of bytes than expected\n");
exit(1);
}
sleep(2);//sleep for 2 seconds
}
return (void *) 0;
}
void *receiveRequest(void *){
char* temp;
char *echoBuffer; /* Buffer for echo string */
unsigned int echoStringLen; /* Length of string to echo */
unsigned int bytesRcvd; /* Bytes read in single recv()]*/
char *partTemp;
unsigned int stringLen;
pthread_mutex_lock(&mutex2);
while(true){
//get the toppest value from the queue
pthread_cond_wait(&cond2, &mutex2);
temp = queue2.front();
pthread_mutex_unlock(&mutex2);
//get the length from the queue
//cp the first four bytes
int k = 0;
stringLen = 0;
while(k<4){
stringLen = stringLen * 10 + temp[k];
k++;
}
//wait for response
echoBuffer = (char *)malloc(5);
if((bytesRcvd = recv(sock, echoBuffer,5, 0)) <= 0){
printf("recv() failed or connection closed prematurely\n");
exit(1);
}
//totalBytesRcvd += bytesRcvd;
//get the length of the string recv
k=0;
echoStringLen = 0;
while(k<4){
echoStringLen = echoStringLen * 10 + echoBuffer[k];
k++;
}
echoBuffer = (char *)realloc(echoBuffer, echoStringLen + 1);
//recive the rest of the string, which is a length of echoStringLen+1
bytesRcvd = recv(sock, echoBuffer, echoStringLen+1, 0);
echoBuffer[echoStringLen] = '\0';
//escape the first 5 bytes for the printing
partTemp = temp;
k=0;
while(k<5){
partTemp ++;
k++;
}
printf("%s\nServer: %s \n", partTemp, echoBuffer);
free(echoBuffer);
//pop the toppest value from the queue
//this is useful for closing the threads
//it can ensure all allocations are freed
pthread_mutex_lock(&mutex2);
queue2.pop();
free(temp);
pthread_mutex_unlock(&mutex2);
}
return (void *) 0;
}
Server Side:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <ifaddrs.h>
#define PORT 0
#define MAXPENDING 5
int main(){
struct sockaddr_in serverAddress, clientAddress; // These stores the network settings
socklen_t serverAddressLength = sizeof(serverAddress), clientAddressLength = sizeof(clientAddress);
int serverSocketID, clientSocketID;
if ((serverSocketID = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
perror("socket() failed");
exit(1);
}
// Specifying preference for IP address and port number lookup
memset(&serverAddress, 0, sizeof(serverAddress)); // Initialize memory for
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress.sin_port = htons(PORT);
if (bind(serverSocketID, (struct sockaddr *) &serverAddress, serverAddressLength) != 0) {
perror("bind() failed");
close(serverSocketID);
exit(1);
}
// Server starts to listen
if (listen(serverSocketID, MAXPENDING) == -1) {
perror("listen() failed");
close(serverSocketID);
exit(1);
}
//The following code is to obtain IP address from ifaddr info from Linux
getsockname(serverSocketID, (struct sockaddr*) &serverAddress, &serverAddressLength);
struct ifaddrs * ifAddrStruct=NULL;
struct ifaddrs * ifa=NULL;
void * tmpAddrPtr=NULL;
getifaddrs(&ifAddrStruct);
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
// is a valid IP4 Address
tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
char addressBuffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
if(ifa->ifa_name[0] == 'e' ){
printf("SERVER_ADDRESS %s\nSERVER_PORT %d\n", addressBuffer, (int) ntohs(serverAddress.sin_port));
break;
}
} else if (ifa->ifa_addr->sa_family==AF_INET6) { // check it is IP6
// is a valid IP6 Address
tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
char addressBuffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
if(ifa->ifa_name[0] == 'e' ){
printf("SERVER_ADDRESS %s\nSERVER_PORT %d\n", addressBuffer, (int) ntohs(serverAddress.sin_port));
break;
}
}
}
if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
// Select attributes
int largestFileDescriptorIndex = serverSocketID;
// We will add clients to the master list, select will use a worker copy of our master list
fd_set master, worker;
//initialize the file descriptor list
FD_ZERO(&master);
FD_ZERO(&worker);
FD_SET(serverSocketID, &master);
// Add keyboard to allow control over server
FD_SET(STDIN_FILENO, &master);
// Specify how long to block and wait for a client to do something
struct timeval fileDescriptorWaitTime;
// Wait for 1 second to check if there is data coming in
fileDescriptorWaitTime.tv_sec = 1;
fileDescriptorWaitTime.tv_usec = 0;
int running = 1, i;
while(running) { // This is the big red switch that makes the server run
worker = master; // Resets the select list
if (select(largestFileDescriptorIndex + 1, &worker, NULL, NULL, &fileDescriptorWaitTime) == -1) {
perror("select() failed");
close(serverSocketID);
exit(1);
}
// Loop through the state of all file descriptors
for (i = 0; i <= largestFileDescriptorIndex; i++) {
// Check if any file descriptor changed state
if (FD_ISSET(i, &worker)) {
// A new client is trying to connect
if (i == serverSocketID) {
// Client connect successfully
if ((clientSocketID = accept(serverSocketID,
(struct sockaddr*) &clientAddress, &clientAddressLength)) != -1) {
// Register client into master list
FD_SET(clientSocketID, &master);
if (clientSocketID > largestFileDescriptorIndex) {
// Update length of list to loop
largestFileDescriptorIndex = clientSocketID;
}
}
}
else if (i == STDIN_FILENO) { // Check keyboard input
fprintf(stdout, "Server is Shutting down\n");
getchar();
running = 0;
continue;
}else
{
char *echoBuffer; /* Buffer for echo string */
int recvMsgSize; /* Size of received message */
int j;
echoBuffer = (char *)malloc(5);
/* Receive message from client, get the first 5 bytes first to know the length of the string*/
if ((recvMsgSize = recv(clientSocketID, echoBuffer, 5, 0)) < 0){
perror("recv() failed");
close(clientSocketID);
FD_CLR(clientSocketID, &master);
}
int stringLen=0, k = 0;//the length of the string
/*convert the char * into an int*/
while(k<4){
stringLen = stringLen*10 + (int)echoBuffer[k];
k++;
}
char *str; // store the string
//string size + 4 bytes + '\0'+strlen(string)+'\0'
str = (char *)malloc(stringLen + 6);
//put the first 5 bytes into the echo string
k = 0;
while(k<5){
str[k] = echoBuffer[k];
k++;
}
free(echoBuffer);
//recieve string of a length of stringLen+1, which is char num + '\0'
echoBuffer = (char *)malloc(stringLen+1);
if ((recvMsgSize = recv(clientSocketID, echoBuffer, stringLen+1, 0)) < 0){
perror("recv() failed");
close(clientSocketID);
FD_CLR(clientSocketID, &master);
}
//set the last char to be null
echoBuffer[stringLen]='\0';
printf("%s\n", echoBuffer);
//deal with the data here
if(echoBuffer[0] <= 'z' && echoBuffer[0]>='a')
echoBuffer[0] = echoBuffer[0] + 'A'-'a';
//operations on data except the first one
for( j = 1; j<stringLen; j++)
{
if(echoBuffer[j]<='z' && echoBuffer[j]>='a' && echoBuffer[j-1] == ' ')
echoBuffer[j] = echoBuffer[j] + 'A'-'a';
else if(echoBuffer[j]<='Z' && echoBuffer[j]>='A' && echoBuffer[j-1] != ' ')
echoBuffer[j] = echoBuffer[j] + 'a'-'A';
}
//store the data into str
k= 0;
while(k<=stringLen){
str[k+5] = echoBuffer[k];
k++;
}
str[stringLen+5] = '\0';
free(echoBuffer);
recvMsgSize = stringLen+6;
/* Send received string */
/* Echo message back to client */
if (send(clientSocketID, str, recvMsgSize, 0) != recvMsgSize){
perror("send() failed");
close(clientSocketID);
FD_CLR(clientSocketID, &master);
}
free(str);
}//operations on the data finishes
}//if the client socket descriptor is in the list
}//loop through all the file descriptors
}//busy waiting
close(serverSocketID);
return 0;
}
When a client disconnects, the client's socket will select as ready-for-read, and then all subsequent attempts to recv() on that socket will return 0, to indicate EOF. Note that this situation is the only time recv() will return 0. It looks like your code is expecting recv() to return -1 in that scenario instead, so it isn't handling that case correctly.
Also it looks like you try to use echoBuffer after free()-ing it, which is undefined behavior and should be avoided. (In fact, why use malloc() and free() at all? Just declare echoBuffer on the stack with a large-enough size, and you won't have to worry about when to free() it)
I have written a C++ demo example. It transfers a file from a server to client.When, I run this program in the local host, it works fine. However, when I run this program over the network the file transfer is incorrect. The image size received is larger than the image size sent. Also, why the same works on the local host? I have tried changing the port number also.
Here is the program -
Server
/** man 2 socket **/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
char msg[] = "Shreyas..first socket prog";
int sock , sock_active;
struct sockaddr_in server, client;
int sent,ret;
unsigned int len;
char buffer[1024];
FILE *fp;
if ( (sock = socket(AF_INET,SOCK_STREAM,0)) == -1 )
//if ( (sock = socket(AF_INET,SOCK_DGRAM ,0)) == -1 )
{
perror("Sock:");
}
server.sin_family = AF_INET;
server.sin_port = htons(15000);
//server.sin_addr.s_addr = INADDR_ANY;
inet_aton("136.170.195.17", &(server.sin_addr));
bzero(&server.sin_zero, 8);
len = sizeof(struct sockaddr_in);
if( ret = (bind( sock, (struct sockaddr *)&server, len)) == -1 )
{
perror("bind :");
}
ret = listen(sock, 0);
while(1)
{
if( (sock_active = accept(sock, (struct sockaddr *)&client, &len)) == -1 )
{
perror("Problem in active socket:");
}
fp = fopen("./Tiger.JPG","rb");
if( fp == NULL )
{
cout<<"Error open file";
return -1;
}
memset(buffer, 1024,0);
int packets = 0;
int count;
//while ( fgets(buffer,1024,fp ) != NULL )
while( ! feof(fp) )
{
packets++;
cout<<"Client IP address is "<<inet_ntoa(client.sin_addr)<<endl;
cout<<"Client Port address is "<<ntohs(client.sin_port)<<endl;
/** Fread is reliable when using to find out the EOF , in feof(fp **/
count = fread(buffer,1,sizeof(buffer),fp);
/** fgets doesn't move the FP correctly */
//fgets(buffer,sizeof(buffer),fp);
cout<<"Read number of bytes ="<<count;
sent = send(sock_active, buffer, sizeof(buffer),0);
cout<<"The number of bytes sent ="<<sent<<"packet number = "<<packets<<endl;
memset(buffer, 1024,0);
}
cout<<"CLose current socket"<<endl;
close(sock_active);
fclose(fp);
}
cout<<"CLosing socket now" <<endl;
close(sock);
return 0;
}
Client socket program -
/** man 2 socket **/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <unistd.h>
using namespace std;
int main(int argc, char *argv[])
{
struct sockaddr_in server;
int ret;
int sock;
int read_val = 1;
unsigned int len;
if ( (sock = socket(AF_INET,SOCK_STREAM,0)) == -1 )
{
perror("Sock:");
}
if( argc != 2 )
{
cout<<"Pass the Server IP "<<endl;
exit(EXIT_FAILURE);
}
server.sin_family = AF_INET;
server.sin_port = htons(15000);
inet_aton(argv[1], &(server.sin_addr));
bzero(&server.sin_zero, 8);
len = sizeof(server);
if ( (ret = connect(sock, (struct sockaddr *)&server,sizeof(server))) == -1)
{
perror("Connect failed:");
exit(-1);
}
char msg[1024];
memset(msg,0,1024);
FILE *fp_w;
fp_w = fopen("./try.JPG","wb");
while( read_val)
{
read_val = recv(sock,(char *)msg,sizeof(msg),0);
fwrite(msg,1,sizeof(msg),fp_w);
}
cout<<"Read is complete"<<endl;
fclose(fp_w);
close(sock);
return 0;
}
May be you should modify this block of code in your client.
while( read_val)
{
read_val = recv(sock,(char *)msg,sizeof(msg),0);
fwrite(msg,1,sizeof(msg),fp_w);
}
recv function will not always receive the number of bytes you want to receive. You have to use the return value of recv to know the number of bytes actually read and use that count to write to file.
I would write this block as,
while( read_val)
{
read_val = recv(sock,(char *)msg,sizeof(msg),0);
if ( read_val > 0)
{
fwrite(msg,1,read_val,fp_w); // I am using `read_val` while writing.
}
}
While working with file/socket io APIs, its not good to assume that it read/wrote exact number of bytes you asked to.
You are making the usual mistake of assuming that recv(), fread(), etc. fill the buffer. They aren't required to do that. They return a count of the number of bytes that were actually received. You have to use that count as the length argument when sending,
You have to send actual number of bytes read:
count = fread(buffer,1,sizeof(buffer),fp);
cout<<"Read number of bytes ="<<count;
if ( count > 0)
sent = send(sock_active, buffer, count,0);
The same for the client while reading:
while( read_val)
{
read_val = recv(sock,(char *)msg,sizeof(msg),0);
if ( read_val > 0) {
fwrite(msg,1,read_val,fp_w)
} else if ( red_val == -1) {
// an error has occured
break;
} else {
// peer has closed the connection
break;
{
}
i have been trying to find how to send a file in chunks in C or C++
i looked at some examples in here did not find good example. i am very new to sockect programming in C/C++
http://beej.us/guide/bgnet/html/single/bgnet.html
any ideas how i need to send files in chunk between client and server? client requesting the file, server sending it back.
i found this for send but not sure about receiving it.
#include <sys/types.h>
#include <sys/socket.h>
int sendall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while(total < *len) {
n = send(s, buf+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
I just wrote this code for receiving files in Client using linux sockets in C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PORT 4118
#define MaxBufferLength 1024 // set the size of data you want to recieve from Server
int main()
{
int sockFd, bytesRead= 1, bytesSent;
char buffer[MaxBufferLength];
struct sockaddr_in server, client;
server.sin_port= htons(PORT);
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
sockFd = socket(AF_INET, SOCK_STREAM, 0);
if(sockFd < 0)
printf("Unable to open socket\n");
int connectionSocket = connect(sockFd, (struct sockaddr *) &server, sizeof(struct sockaddr) );
if(connectionSocket < 0)
perror("connection not established\n");
int fd = open("helloworlds.txt",O_CREAT | O_WRONLY,S_IRUSR | S_IWUSR);
if(fd == -1)
perror("couldn't openf iel");
while(bytesRead > 0)
{
bytesRead = recv(sockFd, buffer, MaxBufferLength, 0);
if(bytesRead == 0)
{
break;
}
printf("bytes read %d\n", bytesRead);
printf("receivnig data\n");
bytesSent = write(fd, buffer, bytesRead);
printf("bytes written %d\n", bytesSent);
if(bytesSent < 0)
perror("Failed to send a message");
}
close(fd);
close(sockFd);
return 0;
}
Hope this helps
Take a look at TCP_CORK (man 7 tcp).
But really, except you want to become a socket/network programming expert, use a library !
Just think of your next problem: data encryption (e.g. HTTPS/SSL). Libraries care for the gory details...
sending and recieving file from tcp socket. Sending the file works however trying to save the file does not work.
#include <cassert>
#include <arpa/inet.h>
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <fstream>
#include <time.h>
#include <strings.h>
#include <sstream>
#include <vector>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/sendfile.h>
#include <fcntl.h>
using namespace std;
using std::endl;
int newscount = 0;
int doccount = 0;
int photocount = 0;
int johns = 0;
vector<string> newsvector;
vector<string> photosvector;
vector<string> docsvector;
void serverlogs(const char*msg) /* writing to log file */
{
time_t rawtime;
struct tm * timeinfo;
time (&rawtime);
timeinfo = localtime(&rawtime);
ofstream file;
file.open("serverlog.txt",ios::app);
if (file.is_open())
{file<<msg;
file<<" # ";
file<<asctime(timeinfo);
file<<"\n";
file.close();
return;
}
else
cout<<"Error Creating log file";
return;
}
void clientlogs(const char*msg) /* writing to log file */
{
time_t rawtime;
struct tm * timeinfo;
time (&rawtime);
timeinfo = localtime(&rawtime);
ofstream file;
file.open("clientlog.txt",ios::app);
if (file.is_open())
{file<<msg;
file<<" # ";
file<<asctime(timeinfo);
file<<"\n";
file.close();
return;
}
else
cout<<"Error Creating log file";
return;
}
void error(const char*msg) /* If there is an error exit the program with err# 1 */
{
perror(msg);
exit(1);
}
void publishdocsvector(const char*msg)
{
docsvector.push_back(msg);
ofstream file;
file.open("docfiles.txt",ios::app);
if (file.is_open())
{
for(int j = 0; j < docsvector.size() ;j++)
{file<<docsvector[j];}
file.close();
}
else
cout<<"Error creating news archive";
return;
}
void publishphotosvector(const char*msg)
{
photosvector.push_back(msg);
ofstream file;
file.open("photofiles.txt",ios::app);
if (file.is_open())
{
for(int j = 0; j < photosvector.size() ;j++)
{file<<photosvector[j];}
file.close();
}
else
cout<<"Error creating news archive";
return;
}
void publishnewsvector(const char*msg)
{
newsvector.push_back(msg);
ofstream file;
file.open("newsfiles.txt",ios::app);
if (file.is_open())
{
for(int j = 0; j < newsvector.size() ;j++)
{file<<newsvector[j];}
file.close();
}
else
cout<<"Error creating news archive";
return;
}
void sendfile(const char*msg)
{
// to be implemented later//
}
int main (int argc, char*argv[]) /*Main Program accepting a port number and something else for arguments */
{
int sockfd, newsockfd, portno, clilen, n,test;
string publish="publish";
string search= "search";
string get="get";
string newsstring = "news";
string docstring = "doc";
string photostring = "photo";
string wrap = "exit";
char buffer[256];
char seats [50];
serverlogs("Server Running");
struct sockaddr_in serv_addr, cli_addr; /* Defines the server address and client address and types of structures with the same format as socket address */
if (argc < 2)
{
fprintf(stderr,"Please provide a port number next time plz, goodbye!");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* If Sock_Dgram then then it will open a udp socket */
if (sockfd < 0)
error("Error opening socket");
bzero((char *)&serv_addr, sizeof(serv_addr)); /* sets the server address to zero usings its reference */
portno = atoi(argv[1]); /*2nd argument vector is the port number and converted into an integer, the first [0] is the running program */
serv_addr.sin_family = AF_INET; /* The structure sockaddr_in has four fields, this is first one and should always be this */
serv_addr.sin_port = htons(portno); /* convert port number into network byte order */
serv_addr.sin_addr.s_addr = INADDR_ANY; /*3rd Field uses Ip address of host machine */
if (bind(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr))<0) /*bind socket to sockfd and address of server ,and needs size of address need struct of sockaddr, see bind man for details*/
error("Couldn't bind socket to address");
listen(sockfd,5);
clilen = sizeof(cli_addr);
serverlogs("going into server loop");
int pid = fork();
if (pid < 0)
serverlogs("error on initial separtion of server and client");
if (pid==0)
{
// server loop later on this will be the child process and client will be main
while (1)
{ /* Server loop loop*/
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, (socklen_t*)&clilen);
if (newsockfd < 0)
/* error("Corrupt log"); */
serverlogs("Connection not accepted");
else (newsockfd > 0);
int ppID = fork();
if (ppID < 0)
serverlogs("A new server process failed to be created");
if (ppID == 0)
{
int uid;
uid = johns;
printf("A new client connected with identity: %d\n", getpid());
close(sockfd);
serverlogs("A john Connected to the server");
printf("my unique id: %d\n", uid);
serverlogs(seats);
bzero(buffer,256);
//n = write(newsockfd,"Each client is a 'john' \n",26);
/* This loop read from socket and writes to other persons sockets */
while(1)
{
bzero(buffer,256);
n = read(newsockfd,buffer,256);
if (n < 0)
printf ("error reading from socket here is the message: %s",buffer);
if (publish[0] == buffer[0])
{
n = write(newsockfd,"What category are you publishing in?(news,photos,documents) \n",62);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
if(buffer[0]==newsstring[0])
{
n = write(newsockfd,"Type the name of the file to publish and wait 10 seconds \n",59);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
publishnewsvector(buffer);
serverlogs(seats);
serverlogs("client is trying to publish a news file:");
serverlogs(buffer);
/*start recieving a file*/
std::ofstream file;
file.open(buffer, std::ios::out | std::ios::binary);
assert(file.is_open());
while (1) {
std::cout << "..";
bzero(buffer,256);
n = read(newsockfd, buffer, sizeof(buffer));
assert(n != -1);
if (n == 0)
break;
file.write(buffer, n);
i++;
}
file.close();
serverlogs("File Transfered successfully");
}
if(buffer[0]==docstring[0])
{
n = write(newsockfd,"Type the name of the file to publish \n",39);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
publishdocsvector(buffer);
serverlogs(seats);
serverlogs("client is tyring to publish a document:" );
serverlogs(buffer);
/*start recieving a file*/
std::ofstream file;
file.open(buffer, std::ios::out | std::ios::binary);
assert(file.is_open());
while (1) {
std::cout << ".";
bzero(buffer,256);
n = read(newsockfd, buffer, sizeof(buffer));
assert(n != -1);
if (n == 0)
break;
file.write(buffer, n);
}
file.close();
serverlogs("File Transfered successfully");
}
if(buffer[0]==photostring[0])
{
n = write(newsockfd,"Type the name of the file to publish \n",39);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
publishphotosvector(buffer);
serverlogs(seats);
serverlogs("client is trying to publish photo file:" );
serverlogs(buffer);
/*start recieving a file*/
std::ofstream file;
file.open(buffer, std::ios::out | std::ios::binary);
assert(file.is_open());
while (1) {
std::cout << ".";
bzero(buffer,256);
n = read(newsockfd, buffer, sizeof(buffer));
assert(n != -1);
if (n == 0)
break;
file.write(buffer, n);
}
file.close();
serverlogs("File Transfered successfully");
}
}
if (get[0] ==buffer[0])
{
n = write(newsockfd,"\n What file do you want to get? \n",35);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
serverlogs(seats);
serverlogs("client wants file:");
serverlogs(buffer);
//** start sending the file**//
FILE* searchfile = 0;
long Size = 0;
searchfile = fopen(buffer,"r");
fseek(searchfile, 0, SEEK_END);
Size = ftell(searchfile);
char *bufferfile = (char*)malloc(Size);
memset(bufferfile, 0, Size);
fseek(searchfile, 0, SEEK_SET);
fread(bufferfile, Size, 1, searchfile);
n = write(newsockfd,bufferfile,256);
fclose(searchfile);
serverlogs("Sent the file to the client");
serverlogs(seats);
}
if (search[0] == buffer[0])
{
bzero(buffer,256);
n = write(newsockfd,"What category are you searching? \n",35);
bzero(buffer,256);
n = read(newsockfd,buffer,256);
serverlogs(seats);
serverlogs("client searching for");
serverlogs(buffer);
if(buffer[0]==newsstring[0])
{
FILE* searchfile = 0;
long Size = 0;
searchfile = fopen("newsfiles.txt","r");
fseek(searchfile, 0, SEEK_END);
Size = ftell(searchfile);
char *bufferfile = (char*)malloc(Size);
memset(bufferfile, 0, Size);
fseek(searchfile, 0, SEEK_SET);
fread(bufferfile, Size, 1, searchfile);
n = write(newsockfd,bufferfile,256);
fclose(searchfile);
}
if(buffer[0]==docstring[0])
{
FILE* searchfile = 0;
long Size = 0;
searchfile = fopen("docfiles.txt","r");
fseek(searchfile, 0, SEEK_END);
Size = ftell(searchfile);
char *bufferfile = (char*)malloc(Size);
memset(bufferfile, 0, Size);
fseek(searchfile, 0, SEEK_SET);
fread(bufferfile, Size, 1, searchfile);
n = write(newsockfd,bufferfile,256);
fclose(searchfile);
}
if(buffer[0]==photostring[0])
{
FILE* searchfile = 0;
long Size = 0;
searchfile = fopen("photofiles.txt","r");
fseek(searchfile, 0, SEEK_END);
Size = ftell(searchfile);
char *bufferfile = (char*)malloc(Size);
memset(bufferfile, 0, Size);
fseek(searchfile, 0, SEEK_SET);
fread(bufferfile, Size, 1, searchfile);
n = write(newsockfd,bufferfile,256);
fclose(searchfile);
}
}
if(buffer[0]==wrap[0])
{
close(sockfd);
close(newsockfd);
johns = johns - 1;
serverlogs("A john left");
return 0;
}
n = write(newsockfd,"\n Waiting for a command I can understand:(publish,search,get,exit)",66);
} /* while loop to listen to commands from client bracket */
}/*what to do when client connected*/
} /*Creating child/zombies */
} /* division between client and server*/
else
{
while (1)
{int ssockfd, pportno, p,peer;
struct sockaddr_in peer_addr;
struct hostent *peerserver;
char bbuffer[256];
printf ("%s \n", "Welcome to the Social");
printf ("%s \n", "Please type the port number of the server \n");
cin>>pportno;
ssockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket Please try again");
printf ("%s \n", "Please type in the hostname of client ie sunlab1.njit.edu \n");
char peers[256];
cin >> peers;
peerserver = gethostbyname(peers);
if (peerserver == NULL)
{
fprintf(stderr,"could not connect to ip address");
peerserver = gethostbyname((const char*)peer);
if (peerserver == NULL)
fprintf(stderr,"still null");
exit(0);
}
bzero((char *) &peer_addr, sizeof(peer_addr));
peer_addr.sin_family = AF_INET;
bcopy((char *)peerserver->h_addr,(char *)&peer_addr.sin_addr.s_addr,peerserver->h_length);
peer_addr.sin_port = htons(pportno);
if (connect(ssockfd,(struct sockaddr *)&peer_addr,sizeof(peer_addr)) < 0)
error("ERROR connecting");
clientlogs("Connected to peer");
clientlogs((const char*)&peer);
printf("Please enter a command, publish,search or get: ");
while (1)
{
bzero(bbuffer,256);
fgets(bbuffer,255,stdin);
char apub[] = "publish";
char asearch[] = "search";
char aget[]="get";
if (bbuffer[0]==apub[0] && bbuffer[1]==apub[1])
{
p = write(ssockfd,bbuffer,strlen(bbuffer));
if (p < 0)
error("ERROR writing to socket");
bzero(bbuffer,256);
p = read(ssockfd,bbuffer,255);
if (p < 0)
error("ERROR reading from socket");
printf("%s",bbuffer); //What category are you publishing in//
bzero(bbuffer,256);
fgets(bbuffer,255,stdin);
p = write(ssockfd,bbuffer,strlen(bbuffer));
clientlogs("Client publishing");
clientlogs(bbuffer);
if (p < 0)
error("ERROR writing to socket");
bzero(bbuffer,256);
p = read(ssockfd,bbuffer,255);
if (p < 0)
error("ERROR reading from socket");
printf("%s",bbuffer); //Type the name of the file//
fgets(bbuffer,255,stdin);
p = write(ssockfd,bbuffer,strlen(bbuffer));
clientlogs(bbuffer);
FILE* searchfile = 0;
long Size = 0;
searchfile = fopen(bbuffer,"r");
fseek(searchfile, 0, SEEK_END);
Size = ftell(searchfile);
char *bufferfile = (char*)malloc(Size);
memset(bufferfile, 0, Size);
fseek(searchfile, 0, SEEK_SET);
fread(bufferfile, Size, 1, searchfile);
p = write(ssockfd,bufferfile,256);
fclose(searchfile);
}
if(bbuffer[0]==aget[0] && bbuffer[1]==aget[1])
{
p = write(ssockfd,bbuffer,strlen(bbuffer));
if (p < 0)
error("ERROR writing to socket");
bzero(bbuffer,256);
p = read(ssockfd,bbuffer,255);
if (p < 0)
error("ERROR reading from socket");
printf("%s",bbuffer); //What file do you want to get? //
bzero(bbuffer,256);
fgets(bbuffer,255,stdin);
p = write(ssockfd,bbuffer,strlen(bbuffer));
if (p < 0)
error("ERROR writing to socket");
clientlogs("client wants file:");
clientlogs(bbuffer);
/*start recieving a file*/
std::ofstream file;
file.open(bbuffer, std::ios::out | std::ios::binary);
assert(file.is_open());
char buffer[255];
while (1) {
std::cout << ".";
bzero(bbuffer,256);
p = read(ssockfd, bbuffer, sizeof(bbuffer));
assert(p != -1);
if (p == 0)
break;
file.write(bbuffer, p);
}
file.close();
serverlogs("File Transfered successfully");
}
if (bbuffer[0]==asearch[0] && bbuffer[1]==asearch[1])
{
p = write(ssockfd,bbuffer,strlen(bbuffer));
if (p < 0)
error("ERROR writing to socket");
bzero(bbuffer,256);
p = read(ssockfd,bbuffer,255);
if (p < 0)
error("ERROR reading from socket");
printf("%s",bbuffer); // what category? //
fgets(bbuffer,255,stdin);
p = write(ssockfd,bbuffer,strlen(bbuffer));
if (p < 0)
error("ERROR writing to socket");
clientlogs("Client searching for file");
clientlogs(bbuffer);
bzero(bbuffer,256);
p = read(ssockfd,bbuffer,255);
if (p < 0)
error("ERROR reading from socket");
printf("%s",bbuffer); //The vector array of the files //
}
if (bbuffer[0]==wrap[0] && bbuffer[1]==wrap[1])
{ p = write(ssockfd,bbuffer,strlen(bbuffer));
exit(0); }
}//end of client loop asking to enter a command
}
}
return 0;
}
The problem I see is file << bbuffer. The ofstream's << operator writes until the first NULL byte. Don't forget your buffer is a string (or better, a char *). So, if bbuffer doesn't contain a NULL byte, your program is likely to crash with a SIGSEGV.
You should use file.write(bbuffer, p) instead of file << bbuffer. Also, there's no need to cleanup your buffer using bzero or memset.
And since you didn't provide a compilable source, I wrote the following (supposing Linux/Unix):
#include <cassert>
#include <iostream>
#include <fstream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sa_dst;
memset(&sa_dst, 0, sizeof(struct sockaddr_in));
sa_dst.sin_family = AF_INET;
sa_dst.sin_port = htons(1234);
sa_dst.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = connect(fd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr));
assert(ret != -1);
std::ofstream file;
file.open("received.bin", std::ios::out | std::ios::binary);
assert(file.is_open());
char buffer[255];
while (1) {
std::cout << "..";
ssize_t p = read(fd, buffer, sizeof(buffer));
assert(p != -1);
if (p == 0)
break;
file.write(buffer, p);
}
file.close();
}
You can test it using netcat on your terminal:
$ nc -l 1234 < some_binary_file &
$ ./program
$ cmp some_binary_file received.bin