Thread: need help with sending file

  1. #1
    Registered User
    Join Date
    May 2002
    Posts
    51

    need help with sending file

    With my program you are supposed to be able to send a file from one computer to another, but this is whats wrong:

    The file size is 6846 bytes, both the sender and receiver knows that and when i cout the size the value is correct on both machines. However the file which i receive is 6941 bytes. The last character of the text-file im sending is repeated 95 times in the end of the received file. Here are the code parts which are important:

    Code:
    //the receiver
    char rcv_byte[1];
    int i = 0;
    
    while(i < size) //the value of size is correct, I've checked
    {
    bytes_rcv = recv(newFD, rcv_byte, 1, 0); //receive one byte at a time
    fout.write(rcv_byte, 1);  //write to the file
    
    tot_recv += bytes_rcv;
    i++;
    }
    
    //the sender
    char send_byte[1];
    int i = 0;
    
    while(i < size)
    {
    fin.read(send_byte, 1);
    bytes_sent = send(sockFD, send_byte, 1, 0);
    tot_sent += bytes_sent;
    i++;
    }
    the end of the file i'm sending looks like this:
    ***321

    the end of the received file looks like this:
    ***32111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111 1

    Does anyone know what could be wrong?

    I'm using win98 on one machine an XP on the other, borland command line tools 5.5.

    Apart from the error mentioned there are no other errors in the program.
    Last edited by finnepower; 03-20-2005 at 09:16 AM.
    I abuse:

    Borland C++ Builder 6 Enterprise Edition

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    847
    i is incremented even if recv failed. I don't know if that is causing your problem but it will cause a problem if there is ever a connection error or you try to receive more then one byte at a time.

  3. #3
    Registered User
    Join Date
    May 2002
    Posts
    51
    Quote Originally Posted by Quantum1024
    i is incremented even if recv failed. I don't know if that is causing your problem but it will cause a problem if there is ever a connection error or you try to receive more then one byte at a time.
    If receive fails a couple of times, then the received file probably should be shorter (not longer). But i can throw in an error check and see if recv or send returns -1 at any time, I'll reply with the results.
    I abuse:

    Borland C++ Builder 6 Enterprise Edition

  4. #4
    Registered User
    Join Date
    May 2002
    Posts
    51
    Both recv and send work perfectly and don't return -1. I suspect it might be an error that has nothing to do with the program, maybe the router adds some bytes...heck I don't know.
    Last edited by finnepower; 03-20-2005 at 10:34 AM.
    I abuse:

    Borland C++ Builder 6 Enterprise Edition

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    847
    Quote Originally Posted by finnepower
    If receive fails a couple of times, then the received file probably should be shorter (not longer).
    Not when you write to the file each time. Regardless of how much data you receive you are writing "size" amount of bytes which you say is correct so there isn't anything I can see in that code that would cause the file to grow larget then size.

  6. #6
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    Let's ignore the network for the moment, it is irrelevant:
    Code:
    while(i < size) //the value of size is correct, I've checked
    {
        fout.write(rcv_byte, 1);  //write to the file
        i++;
    }
    Now, there are a few options on why this loop could be writing more bytes than you want.
    1. ostream::write is misbehaving (very very unlikely).
    2. The compiler or processor is failing to increment i or do the condition check correctly (extremely unlikely).
    3. The size variable is wrong.
    4. It is outputting the correct number of bytes. Could the extra bytes be being added after the loop?

    A good debugging option is to print out the value of i after the loop has completed. Is this the actual code or is this a demo version? People often post cleaned up demo code and, in the process, inadvertently fix the bug.

  7. #7
    Registered User
    Join Date
    May 2002
    Posts
    51
    I fixed the problem. I changed "while(i < size)" to "while(i < (size-95))" (there were 95 extra bytes). Really ugly solution though.
    I abuse:

    Borland C++ Builder 6 Enterprise Edition

  8. #8
    Registered User
    Join Date
    May 2002
    Posts
    51
    [*]ostream::write is misbehaving (very very unlikely).[*]The compiler or processor is failing to increment i or do the condition check correctly (extremely unlikely).[*]The size variable is wrong.[*]It is outputting the correct number of bytes. Could the extra bytes be being added after the loop?[/list]
    A good debugging option is to print out the value of i after the loop has completed. Is this the actual code or is this a demo version? People often post cleaned up demo code and, in the process, inadvertently fix the bug.
    I've fixed it. But i can mention that the value of i was correct at the end. Also size was always correct. I've checked the code a number of times and there are no more send's or recv's after the loop.
    I abuse:

    Borland C++ Builder 6 Enterprise Edition

  9. #9
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    How are you opening the file? Is it possible that the trailing characters are left over because you are not trucating the file when you open it? Your open code should look something like this:
    Code:
      fout.open ("test.zip", ofstream::out | ofstream::trunc | ofstream::binary);
    I fixed the problem. I changed "while(i < size)" to "while(i < (size-95))" (there were 95 extra bytes). Really ugly solution though.
    This is not a good idea. Masking a bug, rather than tracking it down, may work temporarily but it will usually fail spectacularly sooner or later.

    Maybe you could post the original code and we can have a look.

  10. #10
    Registered User
    Join Date
    May 2002
    Posts
    51
    I just open it like this:

    ofstream fout(file);

    file is a char array. I'll use the open command you showed and see what happens.
    I abuse:

    Borland C++ Builder 6 Enterprise Edition

  11. #11
    Registered User
    Join Date
    May 2002
    Posts
    51
    now the file is completely messed up: all newlines in the file are dark rectangles and I also have the 95 extra bytes in the end. Here's the complete code, note that there are variables and pieces of code which the program doesn't use. And when i test it i always receive on the machine I'm listening on and send on the machine that connects (I've marked out the code which you can ignore).

    Code:
    #include <sstream>
    #include <string>
    #include <fstream>
    #include <stdio.h>
    #include <winsock.h>
    
    using namespace std;
    
    string IntToString(int num);
    bool StringToInt(const string &s, int &i);
    void removetext(char *txt, int size, int leave);
    
    int main()
    {
    WSADATA wsaData;
    
    	if(WSAStartup(MAKEWORD(1,1), &wsaData) != 0)
    	{
    	cout<<"Error, WSAStartup failed.\n";
    	return 0;
    	}
    
    char UI = 'x';
    char test = 'n';
    char ui = 'x';
    unsigned short int PORT = 21987;
    
    int sockFD, newFD;
    cout<<"test?\n(y)es/(n)o\n#";
    cin>>test;
    cout<<"\n(l)isten\n(c)onnect\ne(x)it\n#";
    cin>>UI;
    
    	if(UI == 'x')
    	return 0;
    
    	if(UI == 'l')
    	{
    	sockaddr_in mAddr;
    	sockaddr_in tAddr;
    	sockFD = socket(AF_INET, SOCK_STREAM, 0);
    
    		if(sockFD == -1)
    		{
    		cout<<"\nError with call to socket()";
    		cin.get();
    		return 0;
    		}
    
    	mAddr.sin_family = AF_INET;
    	mAddr.sin_port = htons(PORT);
    	
    	
    		if(test == 'y')
    		{
    		mAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    		}
    
    		else
    		{
    		mAddr.sin_addr.s_addr = INADDR_ANY;
    		}
    		
    	memset(&(mAddr.sin_zero), '\0', 8); 		
    
    	if(bind(sockFD, (sockaddr *)&mAddr, sizeof(sockaddr_in)) == -1)
    		{
    		cout<<"\nError with call to bind()";
    		cin.get();
    		return 0;
    		}
    
    		if(listen(sockFD, 5) == -1)
    		{
    		cout<<"\nError with call to listen()";
    		cin.get();
    		return 0;
    		}
    
        int sin_size = sizeof(sockaddr_in);
        newFD = accept(sockFD, (sockaddr *)&tAddr, (int *) &sin_size);
    	
    		if(newFD == -1)
    		{
    		cout<<"\nError with call to accept()";
    		cin.get();
    		return 0;
    		}
    	
    	shutdown(sockFD,2);
    	
    	char *msg = "Connection Established";
    	int len = strlen(msg);
    	int bytes_sent = send(newFD, msg, len, 0);
    	
    	char rcv[22];
    	int bytes_rcv = recv(newFD, rcv, 22, 0);
    	
    	cout<<rcv;
    	
    	cout<<"\n\n(s)end file\n(r)ecieve file\n#";
    	cin>>ui;
    
    		if(ui == 's') //I ALWAYS RUN LISTEN-RECEIVE SO YOU
    //CAN IGNORE EVERYTHING IN THIS IF STATEMENT
    		{
    		bool last = 0;
    		bool small = 0;
    		char buff[512];
    		int size;
    		int tot_sent = 0;
    		char file[16];
    		cout<<"Filename\n#";
    		cin>>file;
    
    	{
    	FILE *pFile; 
    	pFile = fopen(file, "rb"); 
    	fseek(pFile, 0, SEEK_END); 
    	size = ftell(pFile); 
    	fclose(pFile);
    	}	
    	
    		if(size < 512)
    		{
    		last = 1;
    		small = 1;
    		}
    	
    		string s = IntToString(size);
    		const char *itsSize = s.c_str();
    		len = strlen(itsSize);
    		bytes_sent = send(newFD, itsSize, len, 0);
    
    		len = strlen(file);
    		bytes_sent = send(newFD, file, len, 0);
    
    		ifstream fin(file);
    
    		while(tot_sent < size)
    		{
    			if(!last)
    			{
    			fin.get(buff, 512);
    			bytes_sent = send(newFD, buff, 512, 0);
    			tot_sent += bytes_sent;
    			}
    
    			if(last)
    			{
    				if(small)
    				{
    				char *lst;
    				fin.get(lst, size);
    				bytes_sent = send(newFD, lst, size, 0);
    				tot_sent = size;
    				}
    				
    				else
    				{
    				int left = size - tot_sent;
    				char *lst;
    				fin.get(lst, left);
    				bytes_sent = send(newFD, lst, left, 0);
    				tot_sent = size;
    				}
    			}
    
    			if((size - tot_sent) < 512)
    			last = 1;
    		}
    
    		}	//S
    	
    		if(ui == 'r')  //I ALWAYS RUN THIS
    		{
                    bool last = 0;
                    bool small = 0;
                    char file[20];
                    char buff[512];
    		int size;
    		int tot_recv = 0;
    		char fileSize[10];
    		
    		cout<<"\n1";
    		bytes_rcv = recv(newFD, fileSize, 10, 0);
    		cout<<"\n2";
    		removetext(fileSize, 10, bytes_rcv);
    		cout<<"\n3   "<<fileSize;
    		string t;
    		cout<<"\n4";
    		t.assign(fileSize);
    		cout<<"\n5";
    		StringToInt(t, size);
    		cout<<"\n6";
    		cout<<"\nsize:  "<<size;
    	
    		if(size < 512)
    		{
    		last = 1;
    		small = 1;
    		}
    
    		bytes_rcv = recv(newFD, file, 20, 0);
    		cout<<"\nfilename (no remtext):  "<<file;
    		removetext(file, 20, bytes_rcv);
    		cout<<"\nfilename (remtext):  "<<file;
    
    		ofstream fout;
    
    		fout.open(file, ofstream::out | ofstream::trunc | ofstream::binary);
    
    		char rcv_byte[1];
    		int i = 0;
    
    		while(i < size)
    		{
    		bytes_rcv = recv(newFD, rcv_byte, 1, 0);
    		fout.write(rcv_byte, 1);
    			
    			if(bytes_rcv == -1)
    			cout<<"\n-1"<<"  "<<i;
    
    		tot_recv += bytes_rcv;
    		i++;
    		}
    
    	cout<<"\ni: "<<i;
    	cout<<"\ntot_recv: "<<tot_recv;
    	cout<<"\nsize: "<<size;
    		}	//R
    
    	shutdown(newFD, 2);
    	}
    
    	if(UI == 'c')
    	{
    	sockaddr_in mAddr;
    	sockFD = socket(AF_INET, SOCK_STREAM, 0);
    
    		if(sockFD == -1)
    		{
    		cout<<"\nError with call to socket()";
    		cin.get();
    		return 0;
    		}
    
    	char cAddr[16];
    	cout<<"\nConnect to address\n#";
    	cin>>cAddr; 	
    	
    	mAddr.sin_family = AF_INET;
    	mAddr.sin_port = htons(PORT);
    	mAddr.sin_addr.s_addr = inet_addr(cAddr);
    	memset(&(mAddr.sin_zero), '\0', 8);
    
    		if(connect(sockFD, (sockaddr *)&mAddr, sizeof(sockaddr)) == -1)
    		{
    		cout<<"\nError with call to connect()";
    		cin.get();
    		return 0;
    		}
    	
    	char rcv[22];
    	int bytes_rcv = recv(sockFD, rcv, 22, 0);
    	
    		if(bytes_rcv == -1)
    		{
    		cout<<"\nError with call to recv()";
    		cin.get();
    		return 0;
    		}
    	
    	char *snd = "Connection Established";
    	int len = strlen(snd);
    	int bytes_snd = send(sockFD, snd, len, 0);
    	
    	cout<<rcv;
    	
    	int bytes_sent;
    
    	cout<<"\n\n(s)end file\n(r)ecieve file\n#";
    	cin>>ui;
    
    		if(ui == 's') //I ALWAYS RUN THIS
    		{
    		bool last = 0;
    		bool small = 0;
    		char buff[512];
    		int size;
    		int tot_sent = 0;
    		char file[16];
    		cout<<"Filename\n#";
    		cin>>file;
    	{
    	FILE *pFile;
    	pFile = fopen(file, "rb");
    	fseek(pFile, 0, SEEK_END); 
    	size = ftell(pFile); 
    	fclose(pFile);
    	}	
    	
    		if(size < 512)
    		{
    		last = 1;
    		small = 1;
    		}
    	
    		string s = IntToString(size);
    		const char *itsSize = s.c_str();
    		len = strlen(itsSize);
    		bytes_sent = send(sockFD, itsSize, len, 0);
    
    		bytes_sent = send(sockFD, file, 20, 0);
    
    		ifstream fin(file);
    		cout<<"\n8";
    		char send_byte[1];
    		int i = 0;
    
    		while(i < size)
    		{
    		fin.read(send_byte, 1);
    		bytes_sent = send(sockFD, send_byte, 1, 0);
    
    			if(bytes_rcv == -1)
    			cout<<"\n-1"<<"  "<<i;
    
    		tot_sent += bytes_sent;
    		i++;
    		}
    
    	cout<<"\ni: "<<i;
    	cout<<"\ntot_sent: "<<tot_sent;
    	cout<<"\nsize: "<<size;
    
    		}	//S
    	
    		if(ui == 'r')  //YOU CAN IGNORE THIS
    		{
                    bool last = 0;
                    bool small = 0;
                    char *file;
                    char buff[512];
    		int size;
    		int tot_recv = 0;
    		char *fileSize;
    		
    		bytes_rcv = recv(sockFD, fileSize, 10, 0);
    		string t;
    		t.assign(fileSize);
    		StringToInt(t, size);
    	
    		if(size < 512)
    		{
    		last = 1;
    		small = 1;
    		}
    
    		bytes_rcv = recv(sockFD, file, 16, 0);
    
    		ofstream fout(file);
    
    		while(tot_recv < size)
    		{
    			if((size - tot_recv) < 512)
    			last = 1;
    
    			if(last)
    			{
    				if(small)
    				{
    				char *lst;
    				bytes_rcv = recv(sockFD, lst, size, 0);
    				fout.write(lst, size);
    				
    				tot_recv = size;
    				}
    				
    				else
    				{
    				int left = size - tot_recv;
    				char *lst;
    				bytes_rcv = recv(sockFD, lst, left, 0);
    				fout.write(lst, left);
    				
    				tot_recv = size;
    				}
    			}
    			
    			if(!last)
    			{
    			bytes_rcv = recv(sockFD, buff, 512, 0);
    			fout.write(buff, 512);
    			}
    			
    		tot_recv += bytes_rcv;
    		}
    
    		}	//R
    	
    	shutdown(sockFD, 2);
    	}
    
    WSACleanup();
    return 0;
    }
    
    string IntToString(int num) 
    { 
    ostringstream myStream;
    myStream << num << flush;
    
    return(myStream.str());
    } 
    
    bool StringToInt(const string &s, int &i) 
    { 
    istringstream myStream(s); 
    
    if (myStream>>i) 
    return true; 
    
    else 
    return false; 
    } 
    
    void removetext(char *txt, int size, int leave)
    {
    	for(int i = 0;i < (size-leave);i++)
    	{
    	txt[leave+i] = '\0';
    	}
    }
    EDIT:
    i just changed ifstream fin(file) to the open method you showed. I got rid of the dark rectangles but the extra bytes are still there.
    Last edited by finnepower; 03-20-2005 at 12:05 PM.
    I abuse:

    Borland C++ Builder 6 Enterprise Edition

  12. #12
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    Ah, of course, I should have thought of that! You're mixing up binary mode and text mode. First a little background. In Windows, a newline is represented by the two characters "\r\n" (carriage return\line feed). On a mac, a newline is represented by "\r" and on Unix by "\n". For portability, the C standard declares that a newline is represented by "\n". Therefore, when you read a text mode file in Windows, the file functions automatically replace each "\r\n" sequence with the single character "\n". On the other side, when you write a text file, each "\n" is replaced with "\r\n". By now, you should be seeing the problem. Consider your program:
    1. It opens the file in binary mode and gets its size. In this case, it is 6846 bytes.
    2. It opens the file in text mode, reads it, and sends it over the network. Because each "\r\n" has been replaced with "\n", the text is only 6751 characters long.
    3. On the receiving side, it opens the file in text mode. IT correctly writes out 6751 characters. Because each "\n" is automatically replaced with "\r\n", at this point, the file is the correct size, 6846 bytes.
    4. Now the problem begins. The program keeps writing up until it reaches the binary size of the file. This is responsible for the extra characters.

    The simplest solution would be to open the file, for both input and output, in binary mode. This would avoid the newline translation. A better solution would be to read the text file into a string or vector so that you know its size before you send it.

  13. #13
    Registered User
    Join Date
    May 2002
    Posts
    51
    Thanks alot! The extra bytes are gone and the received file looks exactly as the original. Now I'll just change it so you can pass the filename and destination as a command-line argument, but that's nothing you need to worry about.
    I abuse:

    Borland C++ Builder 6 Enterprise Edition

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Need Help Fixing My C Program. Deals with File I/O
    By Matus in forum C Programming
    Replies: 7
    Last Post: 04-29-2008, 07:51 PM
  2. Basic text file encoder
    By Abda92 in forum C Programming
    Replies: 15
    Last Post: 05-22-2007, 01:19 PM
  3. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 08:39 AM
  4. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM
  5. Need a suggestion on a school project..
    By Screwz Luse in forum C Programming
    Replies: 5
    Last Post: 11-27-2001, 02:58 AM