How to send and receive data socket TCP (C/C++) [duplicate] - c

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the correct way of reading from a TCP socket in C/C++?
I'm trying to develop a TCP client/server. My problem is, when I try to send the data from cliente I do it in one sent.
But my problem appears when I try to receive the data with a specific structure, I mean, the first 8 bytes set a date, the next 10 a name, and undefined number of bytes set a text (this text ends with /r/n/r/n)
The client sends as follows:
char date[8];
char name[10];
char msg[4096];
strcpy(msg,"12/10/12"); //8 bytes
strcat(msg,"Kevin Fire"); //10 bytes
strcat(msg,"abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde\r\n\r\n");
nbytes_sent = send(sock,(char *)msg,sizeof(msg),0);
printf("Bytes_sent: %s -> %i\n",msg,nbytes_sent);
And the server try to parse the data from socket as follows:
char date[8];
char name[10];
char * text;
char buf[1024];
int i=0;
for(i=0; i < 8; i++)
date[i] = '\0';
for(i=0; i < 10; i++)
name[i] = '\0';
nbytes_read=recv(sclient,(char *)date,sizeof(date),0);
if(nbytes_read > 0){
printf("Date: %s (%i)\n",date,nbytes_read);
//cout.flush();
nbytes_read=recv(sclient,(char *)name,sizeof(name),0);
if(nbytes_read > 0){
printf("Name: %s (%i)\n",name,nbytes_read);
//cout.flush();
nbytes_read=recv(sclient,(char *)buf,sizeof(buf),0);
strcpy(text,buf);
while(nbytes_read > 0){
nbytes_read=recv(sclient(char*)buf,sizeof(buf),0);
strcat(text,buf);
}
}
}
printf("Date: %s. Name: %s. Text: %s\n",date,name,text);

Here's a simple "receive all" function:
int recv_all(int sockfd, void *buf, size_t len, int flags)
{
size_t toread = len;
char *bufptr = (char*) buf;
while (toread > 0)
{
ssize_t rsz = recv(sockfd, bufptr, toread, flags);
if (rsz <= 0)
return rsz; /* Error or other end closed cnnection */
toread -= rsz; /* Read less next time */
bufptr += rsz; /* Next buffer position to read into */
}
return len;
}

One (repeated) mistake is:
nbytes_read=recv(sclient,(char *)date,sizeof(date),0);
recv() does not null terminate. This means date will not have a null terminator if sizeof(date) bytes is read. This is a problem when a non-null terminated string is passed as an argument to printf() with "%s" format specifier. If the string is non-null terminated you may see garbage characters appearing after the actual string data. You need to read one less than the target buffer and null terminate or use the format specifier "%*.s" that does not require null termination:
printf("%.*s", n, s); /* Prints first 'n' bytes from 's'. */
Note you can initialise a char[] to all nulls instead of using a for:
char date[8] = "";
or you can use memset().

Adding to #hmjd's find:
declared at the var decls is your text pointer...
char * text;
then later...
strcpy(text,buf);
while(nbytes_read > 0){
nbytes_read=recv(sclient(char*)buf,sizeof(buf),0);
strcat(text,buf);
}
Maybe try setting that 'text' pointer to something beside a random stack value will help as well.
Continuing the barrage, though the following will not necessarily blow up, your date variable as:
char date[8];
on both client and server side The client variable isn't used at all. The server variable, however is:
nbytes_read=recv(sclient,(char *)date,sizeof(date),0);
if(nbytes_read > 0){
Problem is, the date you sent is, in fact, 8 chars wide already: "12/10/12". Therefore, even if you firm-up a null terminator on the end of your string, which you should always do regardless (good practice):
date[ sizeof(date)/sizeof(date[0])-1 ] = 0;
you'll be truncating off the last char of your date.
There are other things wrong with this; we've only pointed out a few. Think about sending length-prefixes with each of these data values in the array, with checks or range to ensure you get what you expected.
Finally, spending some time on the business-end of a debugger would probably do you very well, especially on the server side.

Related

Pointers and char arrays from strings

Hi I have been reading for hours and still can't grasp the conversions between
{
char i ="adf";
char foo[];
char bar[256];
}
and adding * and & makes it more confusing
I have some code that is working.
int TX_SEND(char send[])
{
unsigned char *p_tx_buffer;
p_tx_buffer = &send[0];
strcat(send, "\r");
// Write to the port
int n = write(fd,&send[0],3);
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
code is working but I need help with 2 parts.
I want to be able to run this function like kind of like printf IE TX_SEND("AT+CGMSD=STUFF"); but I am stuck
but before hand I do this alot.
char txsend[] = "at";
TX_SEND(txsend);
Also inside my TX_WRITE() I am using write(fd,&send[0],3), but it is hardcoded to send 3 bytes from send[]. I want this to be dynamic so I can just send strings at any length (realistically they will be less than 300 ASCII chars always). I tried to do something with a pointer in there but gave up (*p_tx_buffer was my beginning attempt).
i think you want
int TX_SEND(char *send)
{
int n = write(fd,send,strlen(send));
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
you cannot tack on \n to send with strcat. I would add it in the calling function, or declare an intermediate buffer and sprintf to it
like this
int TX_SEND(char *send)
{
char buff[50]; // i dont know a good max size
snprintf(buff, sizeof(buff), "%s\n", send);
int n = write(fd,buff,strlen(buff));
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
I'm not going to go through your code line-by-line, but I urge you to focus on these facts:
chars are chars and strings are strings, and never the twain shall meet. (They're totally different.)
'x' is a character constant.
"x" is a string constant.
A string is an array of characters (terminated by '\0').
When you mention an array (including a string) in a context where you need its value, what you get is a pointer to the array's first element.
When you put a & in front of something, what you get is a pointer to that something.
When you put a * in front of a pointer, what you get is the thing that the pointer points to.
Putting this together, we could write
char str[] = "xyz";
char *p = str; /* per rule 5, this is fine, and p gets a pointer to str's first element */
char c = *p; /* per rule 7, c gets the first character of str, which is 'x' */
printf("%c\n", c);
If you're just starting with C, you may not have come across rule 5 yet. It will probably surprise you at first. Learn it well, though: you'll never understand arrays and pointers in C without it.

XOR Encrypted Message length is showing wrongly in C [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Im Encrypting the Original Messages using XOR algorithm by following code in C program. And Finally it gives another different value that message has encrypted. It should return same length even after the message has encrypted.
But, Using strlen(encrypted) it gives less value than original message length. I couldn't recognize why the length of XOR encrypted message is showing less than the original message length. Please find the following the code to solve my problem.
Thanks in Advance!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char* XORCipher(char* data, char* key, int dataLen, int keyLen) {
char* output = (char*)malloc(sizeof(char)*dataLen);
for(int i = 0; i < dataLen; ++i) {
output[i] = data[i] ^ key[i % keyLen];
}
return output;
}
int main(){
char *msg = "This is a Message from Boss";
char *key = "nandha";
int dataLen = strlen(msg);
int keyLen = strlen(key);
char *encrypt = XORCipher(msg,key,dataLen,keyLen);
printf("\nEncrypted msg is :\n %s",(char*)encrypt);
//The Length of encrypted char size is showing wrongly.
printf("size of Encrypted msg is: %d\n",strlen(encrypt));
encrypt = XORCipher(encrypt,key,strlen(encrypt),keyLen);
printf("\nOriginal msg converted is : %s\n",encrypt);
return 0;
}
When you perform these XOR operations on your string, the resulting values could fall outside the range of printable characters. In particular, if a plaintext character happens to match the key character used to encode it the result will be 0.
In C, a string is actually a sequence of characters terminated by a null byte, i.e. a byte with value 0. Any function that operates on strings looks for this byte to denote the end of the string.
Because your encoding can generate null bytes, your encrypted message is not a string but an array of bytes. Attempting to use a string function on the encrypted message can cause it to stop processing in the middle of the message if it contains a null byte. If the message does not contain a null byte, these string functions will continue to read past the end of the character array until it finds one. Reading past the end of an array or dynamically allocated block of memory invoked undefined behavior.
You need some other way to know how long the encrypted message is. In the case of the XOR encoding you're doing this is easy: the length of the ciphertext is the same as the length of the plaintext. So when decoding, pass in dataLen for the ciphertext length. To print the ciphertext, you need to loop through the bytes and print each one individually rather that trying to print it as a string (which it is not).
Also, after you've decoded, you still don't have a string because there was no null terminating byte added to the end of the decrypted message. You can do this manually after calling decrypting:
// pass in plaintext length as ciphertext length since they are the same
encrypt = XORCipher(encrypt,key,dataLen,keyLen);
// null terminate decrypted string
encrypt[dataLen] = '\0';
The buffer allocated inside of XORCipher doesn't currently allocate enough space for the null terminator, so you need to increase this by 1 to allow for this:
// no need to cast the return value of malloc
// sizeof(char) is guaranteed to be 1, so no need to multiply by it
char* output = malloc(dataLen + 1);
C strings are character arrays that are null terminated. When you allocate your encrypted array with the length of the string, you don't leave room for null termination, so strlen is unable to tell when the string ends, thinking the string ends outside of the actual memory that you allocated. This modification to your xor function will make it work.
char* XORCipher(char* data, char* key, int dataLen, int keyLen) {
char* output = (char*)malloc(sizeof(char)*dataLen+1);
output[dateLen] = 0;
for(int i = 0; i < dataLen; ++i) {
output[i] = data[i] ^ key[i % keyLen];
}
return output;
}
Additionally, if you're xor function gives 0 as an output, strlen will see that as the end of the string, which would give you a string length shorter than the expected output.
Update: I have tested the code and it works.
char* XORCipher(char* data, char* key, unsigned long dataLen, unsigned long keyLen) {
char* output = (char*)malloc(sizeof(char)*dataLen+1);
output[dataLen] = 0;
for(int i = 0; i < dataLen; ++i) {
output[i] = data[i] ^ key[i % keyLen];
}
return output;
}
void printLn(char* toPrint, unsigned long len){
for (unsigned long i = 0; i < len; i++) {
printf("%c", toPrint[i]);
}
printf("\n");
}
int main(){
char *msg = "This is a Message from Boss";
char *key = "nandha";
unsigned long dataLen = strlen(msg);
unsigned long keyLen = strlen(key);
printLn(msg, dataLen);
char* xorMessage = XORCipher(msg, key, dataLen, keyLen);
printLn(xorMessage, dataLen);
xorMessage = XORCipher(xorMessage, key, dataLen, keyLen);
printLn(xorMessage, dataLen);
return 0;
}
Be reminded that xoring can result in null characters in the array that you've allocated, resulting in a terminating character which you might have not intended. To compensate for this, I have added a function to print out based on length since you know this information based on your msg. After xoring twice you should have your original string back, which I my code verified.

Reading Data in C From Socket Until End Character

EDIT: It has been proven in the comments that defining the length instead should produce the same results and would not use any significant extra data. If you are looking for a way to send data between machines running your program(s), sending the length is better than reading until a terminating character. BonzaiThePenguin has some very good points you should look at.
But for educational purposes: I never found good example code that does this for standard C sockets that handles situations where the data is not all received in one packet, or multiple separate messages are contained within one packet. Simply calling recv repeatedly will not work in all cases.
This is one of those questions where I've answered it myself below, but I'm not 100% confident in my response.
It isn't 'dangerous to allow the client to specify the size of the message it is sending'. Most of the protocols in the word do that, including HTTP and SSL. It's only dangerous when implementations don't bounds-check messages properly.
The fatal flaw with your suggestion is that it doesn't work for binary data: you have to introduce an escape character so that the terminating character can appear within a message, and then of course you also need to escape the escape. All this adds processing and data copying at both ends.
Here is what I came up with. I cannot guarantee that this is perfect because I am not a professional, so if there are any mistakes, I (and anyone else looking for help) would greatly appreciate it if someone would point them out.
Context: socket is the socket, buffer is the array that stores all network input, line is the array that stores just one message extracted from buffer (which is what the rest of your program uses), length is the length of both inputted arrays, and recvLength is a pointer to an integer stored outside of the function that is meant to be 0 initially and should not be freed or modified by anything else. That is, it should persist across multiple calls to this function on the same socket. This function returns the length of the data outputted in the line array.
size_t recv_line(int socket, char* buffer, char* line, size_t length, size_t* recvLength){ //receives until '\4' (EOT character) or '\0' (null character)
size_t readHead = 0;
size_t lineIndex = 0;
char currentChar = 0;
while (1){
for (; readHead < *recvLength; readHead = readHead + 1){
currentChar = buffer[readHead];
if (currentChar=='\4' || currentChar=='\0'){ //replace with the end character(s) of your choice
if (DEBUG) printf("Received message===\n%s\n===of length %ld\n", line, lineIndex+1);
memcpy(buffer, buffer + readHead + 1, length-(readHead)); //shift the buffer down
*recvLength -= (readHead + 1); //without the +1, I had an "off by 1" error before!
return lineIndex+1; //success
}
if (readHead >= length){
if (DEBUG) printf("Client tried to overflow the input buffer. Disconnecting client.\n");
*recvLength = 0;
return 0;
}
line[lineIndex] = currentChar;
lineIndex++;
}
*recvLength = recv(socket, buffer + readHead, length, 0);
}
printf("Unknown error in recv_line!\n");
return 0;
}
Simple example usage:
int function_listening_to_network_input(int socket){
char netBuffer[2048];
char lineBuffer[2048];
size_t recvLength = 0;
while (1==1){
size_t length = recv_line(socket, netBuffer, lineBuffer, 2048, &recvLength);
// handle it…
}
return 0;
}
Note that this does not always leave line as a null-terminated string. If you want it to, it's easy to modify.

Socket c bytes received but I can't print the String

I use this code to receive a String from a Java server in a C client.
if( recv( to_server_socket, &reply, sizeof( reply ), MSG_WAITALL ) != sizeof( reply ) )
{
printf( "socket read failed");
exit( -1 );
}
printf( "got reply: %d\n", ntohl( reply ) );
char buf[512];
ssize_t nbytes=0;
int byte_count;
byte_count = recv(to_server_socket, buf, sizeof buf, 0);
printf("recv()'d %d bytes of data in buf\n", byte_count);
buf[byte_count] = '\0';
printf("String : %s\n",buf);
For example, when the Java server sends this String
bZzrEcyVEmjmIf
I got this result
recv()'d 16 bytes of data in buf String :
so I received 16 bytes but the
printf("String : %s",buf);
don't show me anything.
The server sent this String
TYvuDbbKALp3scp
I tried this code
int i=0;
while(i<byte_count){
printf("String : %c\n",buf[i]);
i++; recv()'d 17 bytes of data in buf
and for result I have
String : String : String : String : T String : Y String : v String
: u String : D String : b String : b String : K String : A String : L
String : p String : 3 String : s String : c String : p
Are you sure your characters are printable?
Use something like this to see what you received:
for (int i = 0; i < byte_count; i++)
{
printf("%02x ", (unsigned int) buf[i]);
}
printf("\n"); // flush stdout
It appears that Java is sending a length-prefixed string. The first two bytes correspond to the length field. These two bytes determine how many bytes follow. Here's how I'd serialise and print that:
unsigned int str_len = buf[0] * 256 + buf[1];
char *str = buf + 2;
/* printf("%.*s\n", str_len, str); // You could use this,
instead of the following two lines: */
fwrite(str, 1, str_len, stdout);
putchar('\n');
A byte with the value 0 denotes the end of a string, in C. This explains why the string pointed to by buf appears to be empty. It also explains why any embedded characters in your length-prefixed string that have the value 0 will cause the commented out printf in my code to cease printing the string.
It's a character value that doesn't have a well-defined visual representation. This explains why embedded characters in your length-prefixed string will cause fwrite to print awkward-looking characters.
The string being sent contains 14 characters. If the C application receives 16 bytes for it, there are 2 extra bytes. Probably they are placed at the beginning of the buffer and note the length of the string being sent (this is how I would send strings over a TCP socket since message boundaries are not guaranteed to be kept there). And if the first byte is zero, you will surely see nothing.
Try printing out values of all the 16 bytes from the buf.
I would also advise to send and parse a length of the string before the actual characters and then read from the socked the appropriate (known) number of bytes, otherwise you risk to get an incomplete string or two concatenated strings.
The stdout stream is buffered, your printf should include \n to flush the stream
printf("String : %s\n",buf);
or
fflush(stdout);
struct _received_data
{
unsigned char len_byte1;
unsigned char len_byte2;
char *str;
} received_data;
Then, once your receive the buffer:
received_data *new_buf = (received_data*) buf;
printf( "String = %s", new_buf->str);
Note that the buffers that are used in send & recv are meant to carry binary data. If data being transmitted is a string, it needs to be managed (ie., adding '\0' and end of buffer etc). Also, in this case your Java server is adding length bytes following a protocol (which the client needs to be aware of).

Reading From A Buffer and Storing the line in an array

I am trying to make a simple client and server. Right now I am able to prints the contents of a file out to the screen. I would now like to store every line i read from the buffer into an array. I have attempted this but for some reason it always just adds the last line received from the buffer. Can anyone point out where I have gone wrong
int getFile (char path[256], int fd)
{
char buffer[256];
char bufferCopy[256];
char arguments[1000][1000];
int total = 0;
char * ptr;
while(read(fd, buffer, 256) != NULL)
{
char * temp;
strcpy(arguments[total], buffer);
total++;
}
for(int i = 0; i < total; i++)
{
printf("\n %s", arguments[i]);
}
}
Your read call doesn't read lines, it reads up to 256 bytes from fd. read also doesn't know anything about null terminators so there is no guarantee that buffer will hold a string (i.e. have a null terminator) and hence no guarantee that strcpy will stop copying at a sensible place. You're almost certainly scribbling all over your stack and once you do that, all bets are off and you can't expect anything sensible to happen.
If you want to read lines then you might want to switch to fgets or keep using read and figure out where the EOLs are yourself.

Resources