Got a huge problem. Let's say, that I have pointer to a large string (~1500 characters) and I want to print it. What I get in the result is only a part of that string. After the program prints that part it asks me for a newline. After I press enter the program prints the rest of the string and terminates. It happens when I try to run my program in terminal or with IDE. If I try to debug it, it works perfectly. I need it to print whole string without terminating the program. So, here's the code (there's lots of mistakes in the code):
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netdb.h>
#include<string.h>
#define SOCKET int // Apibreziame sinonima 'int' tipui, kad butu
// unix ir WIN sistemoms bendras kodas dirbant
// su soketu deskriptoriais.
#define closesocket close // Apibreziame sinonima close () funkcijai
// closesocket (), kuris yra analogas Windows
// tipo sistemose. Tai del kodo suvienodinimo.
#define INVALID_SOCKET -1 // Apibreziame del kodo suvienodinimo, klaidos
#define SOCKET_ERROR -1 // situacijai nusakyti konstantas, kurios WINSOCK'o
#define MAX_CH 255
#define POP3_PORT 110
#define MAXLEN 1024
int main()
{
SOCKET socketE;
struct sockaddr_in servaddr;
struct hostent* h = NULL;
char* Packet = NULL;
Packet = (char*)malloc(MAX_CH);
memset(Packet, 0, sizeof(Packet));
printf("POP3 server: ");
gets(Packet);
/*******{
client connects to the mail server and other stuff
server sends greeting message
client receives greeting message
}*******/
if (!strstr(Packet,"+OK")) {
print_error(Packet);
}
else {
printf("%s", Packet);
int printedData = 0;
while (1) {
Packet = (char*)realloc(NULL, 1);
memset(Packet, 0, sizeof(Packet));
gets(Packet);
strcat(Packet, "\n");
if (SOCKET_ERROR == SendPacket(&socketE, Packet)) {
print_error("Error on sending data to mail server.\n");
}
memset(Packet, '\0', sizeof(Packet));
if (SOCKET_ERROR == ReceivePacket(&socketE, &Packet)) {
print_error("Error on receiving data from mail server.\n");
}
if (!strstr(Packet,"+OK")) {
fwrite(Packet, 1, strlen(Packet), stdout);
break;
}
printf("%s", Packet); //THIS IS WHERE THE PRINT PART COMES
}
}
close(socketE);
return 0;
}
Okey, so I have found out that this if clause (I mean, even if this if is false) stops program from printing all the content. If I remove/comment it, I got my program working correctly. Is it possible, that this one causes all the problems?
if (!strstr(Packet,"+OK")) {
fwrite(Packet, 1, strlen(Packet), stdout);
break;
}
This:
Packet = (char*)realloc(NULL, 1);
memset(Packet, 0, sizeof(Packet));
causes undefined behavior. It allocates a single byte (why would you ever do this?) and then clears sizeof(Packet) bytes, which on most typical systems today is either 4 or 8 bytes. Thus, it writes outside the allocated memory. Note that sizeof cannot track dynamic allocations, so this whole pattern is wrong.
Also, please note that dynamic memory allocation can fail; you must check the return value of every call to realloc() before relying on the returned pointer being valid. If it's NULL, you can't access through it.
Further, just like with malloc(), please don't cast the return value of realloc() in C.
Try to add flush after printf:
printf("%s", Packet);
fflush(stdout);
printf use stdout, which is line buffered. So printf texts can be partly flushed (printed) if there is no '\n' in the end of the string.
In your case unflushed text is flushed when you type the newline.
Stdout is line buffered and characters in the stdout stream are saved until a newline is output or input is read from any stream attached to a terminal device, or if the stream buffer gets full.
so you may either put the '\n' character in your printf like printf("%s\n",Packet); or just disable the stdout buffering using setbuf(stdout, NULL); for printf to print the complete string
Related
I'm using sockets in C, I have a client that will send a message and the size of the message and the server that will receive this message in buffers of shorter size. The message is being sent correctly, but I'm having problems when I try to concatenate all the buffers in a single string.
The client:
char *buffer = "Hello from the client you're receiving this message";
int bytes_sent;
long msgSize = strlen(buffer);
printf("Buffer Size: %ld\n", msgSize);
int msgFileSize = send(SocketFD, &msgSize, sizeof(msgSize),0);
bytes_sent = send(SocketFD, buffer, strlen(buffer), 0);
The server:
char buffer[8];
ssize_t recsize;
long msgSize;
int msize = recv(ConnectFD, &msgSize, sizeof(msgSize), 0);
int total_byt = 0;
printf("Full Message Size: %ld\n", msgSize);
char full_msg[msgSize];
while (total_byt < msgSize) {
recsize = recv(ConnectFD, (void*)buffer, sizeof buffer, 0);
total_byt += recsize;
strcat(full_msg, buffer);
if (recsize < 0) {
fprintf(stderr, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("recsize: %d\n ", (int)recsize);
sleep(1);
printf("datagram: %.*s\n", (int)recsize, buffer);
}
printf("full message: %s\n", full_msg);
The output of the server looks like this:
Full Message Size: 51
recsize: 8
datagram: Hello fr
recsize: 8
datagram: om the c
recsize: 8
datagram: lient yo
recsize: 8
datagram: u're rec
recsize: 8
datagram: eiving t
recsize: 8
datagram: his mess
recsize: 3
datagram: age
full message: ��9�Hello from the client you're receiving this message mess
Few problems here.
strlen returns length excluding the null char.
long msgSize = strlen(buffer);
Thus you need to have 1 additional place to hold null char.
char full_msg[msgSize+1];
full_msg[0] = '\0';
There is undefined behavior with strcat as buffer is not null terminated.
recsize = recv(ConnectFD, (void*)buffer, sizeof buffer, 0);
strcat(full_msg, buffer);
use
strncpy(full_msg, buffer, sizeof buffer);
Finally null terminate the full_msg after loop to be sure.
while (total_byt < msgSize) {
….
}
full_msg[total_byt] = '\0';
It looks like your full message variable is not initialized. It is starting out with random data in it, which is causing your unexpected results. Use the following code to initialize it:
char full_msg[msgSize] = "";
Also, using strcat in the way you are is not safe. You must keep track of how much space is left in full_msg or you will have a buffer overrun situation. strncat is the function that can solve this problem.
There's absolutely no point reading into a separate buffer and then concatenating that into another buffer. Just read directly into full_msg.
Even if you were going to append block by block, strcat is not the right way to do it. strcat needs to start by finding the current end of the output buffer, which it can only do by sequentially scanning from the beginning looking for a NUL byte. As the buffer gets more and more data, those scans get longer and longer, leading to quadratic time complexity. This particular unnecessarily quadratic append is often called a "Schlemiel the Painter" algorithm.
The scan is unnecessary because you already know where the new data should be appended, since you carefully keep track of how many bytes you've already read. So each successive block should be placed total_byt bytes past the beginning of the buffer. (That is, at location full_msg+totalbyt.) You also know how long the data to append is, so you can use memcpy to put the newly-read chunk in the right place.
Uding memcpy will also avoid the problems which will occur if data can contain NUL bytes. (Since strcat returns immediately when it encounters a NUL, your current code will not work on messages which do include NUL.)
Note thatrecv does not NUL-terminate the input received, so your strcat will also do the wrong thing if the recv doesn't fill the buffer (and it only works with the buffer as written because it happens to be the case that
There is at least one other problem with your code: nothing guarantees that recv will stop reading at the end of a message, since the sockets library doesn't know where TCP messages end. (UDP message endpoints are marked, but you can't receive a UDP message in multiple chunks.) Again, since you keep track of the number of bytes read, and you know the length of the message (once you've read that data, at least), you can easily work out what the maximum number of bytes to read is.
I am trying to learn client server model in Linux and I have setup two C files namely server.c and client.c. These are the code snippets that I seem to have problems with.
server.c code snippet
char* message = "<query>\n";
write(client_socket_filedescriptor, message, sizeof(message));
client.c code snippet
char* message = "<query>\n";
read(socket_filedescriptor, buffer, sizeof(buffer));
printf("%s", buffer);
printf("\n\n");
printf("%s", message);
Now when I run my server and then when I run my client, I expect the printf statements to print the same strings that is <query>\n, but I keep getting different outputs for buffer and message variables.
The output looks a bit like this when I run client code.
Output image
As you see, these two strings are different. I am trying to simulate a typical TCP handshake and I want to make sure that these two strings are same and then client will start writing or doing something with that server. But I am having this trivial problem. Could anyone tell my how to resolve it? I plan to use strcmp to compare buffer and message variables, but as it stands now, strcmp doesn't return 0 since these are different strings afterall.
You are ignoring the count returned by read(). It can be -1, indicating an error, or zero, indicating end of stream, or a positive number, indicating how many bytes were received. You cannot assume that read() fills the buffer, or that a single send() or write() corresponds to a single recv() or read().
In detail:
write(client_socket_filedescriptor, message, sizeof(message));
You are only sending four bytes, the size of the pointer. And you're ignoring the return value. It should be
int count = write(client_socket_filedescriptor, message, strlen(message));
if (count == -1)
perror("write"); // or better
char* message = "<query>\n";
read(socket_filedescriptor, buffer, sizeof(buffer));
That should be
int count = read(socket_filedescriptor, buffer, sizeof(buffer));
if (count == -1)
perror("read"); // or better
else if (count == 0)
; // end of stream: the peer has disconnected: close the socket and stop reading
else
Back to your code:
printf("%s", buffer);
That should be
printf("%.*s", count, buffer);
I plan to use strcmp()
You should plan to use strncmp(), with count above as the length parameter. In any case you can't assume the input ends with a null unless you (a) ensure you send the null, which you aren't, and (b) write a read loop that stops when you've read it.
I have the following code in server.c
while (1) {
char msg[1024];
recv(fd, msg, 1024, 0);
}
From client, first, I sent "hello world".
And then I received "hello world" in server.
I then sent "hexx" to server.
But I received "hexxo world" on server.
It seems as if msg wasn't cleared fully.
Please let me know what I'm doing wrong.
Cheers.
You are allocating 1024 bytes for message and never zeroing that data. You are just reading into the same buffer over and over. First pass it reads "hello world" in the second pass you are putting "hexx" in the same starting address resulting in "hexxo world"
As DoxyLover mentions you can null terminate the newly read string and get what you are looking for.
tcp recv not clearing old data
Who said it would? Not that it should be necessary. You're ignoring the count returned by recv(). After calling recv(), there are three possibilities:
Return value of -1: an error; call perror().
Return value of 0: end of stream: close the socket and exit the read loop.
Return value is positive: you have received exactly that many bytes into your buffer, and you should not assume that any data beyond that count is valid.
At present you're doing none of these things correctly.
read() does not null terminate the buffer. Therefore, you are seeing the old data left over in the buffer.
What you want is something like:
while (1) {
char msg[1024];
ssize_t n = recv(fd, msg, 1023, 0);
if (n >= 0)
msg[n] = '\0';
}
Note that I am limiting the read to one less than the size of the buffer to allow space for the null byte. Obviously, this only works with text data. With binary data, you need to record the return value from read() and use that as a byte count when processing the buffer. For example, to copy data from one socket to another:
while (1) {
char msg[1024];
ssize_t n = recv(fd, msg, 1024, 0);
if (n > 0)
send(second_fd, msg, n, 0);
}
All of this is very simplified - you need error checking, check the return from read() to make sure any bytes were received, check the return from send() to make sure all of the byte were sent, etc.
Code for client:
/* Packet struct */
struct
{
int x;
int y;
char mess [5];
} Packet;
/* Assigning values to packet */
Packet.x = 5;
Packet.y = 25;
strcpy(Packet.mess, "Hell");
/* Send packet */
int bytesTransmitted = send(socketID, &Packet, sizeof(Packet), 0);
/* Check transmission */
if (bytesTransmitted < 0)
{
printf("Error sending message!\n");
return 1;
}
else
{
printf("Message sent successfully! Message size: %lu, bytes trasnmitted: %d", sizeof(message), bytesTransmitted);
}
/* End of pogram */
return 0;
Code for server:
struct
{
int x;
int y;
char mess [5];
} Packet;
unsigned int clientLength = sizeof(clientAddress);
/* Main loop */
while (1)
{
int listenSocket = accept(socketID, (struct sockaddr*)&clientAddress, &clientLength);
if (listenSocket > 0) /* Connection accepted */
{
printf("Received connection from: %s:%d\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
if (recv(listenSocket, &Packet, sizeof(Packet), 0) > 0)
{
printf("Message: %s\n x:%d\n y:%d", Packet.mess, Packet.x, Packet.y);
/* HERE IS THE PROBLEM */
}
}
}
Output from server at first connection:
Received connection from: 127.0.0.1:48648
Message: Hell
x:5
y is missing.
I terminate the client and restart it without touching the server.
Output from server:
y:25 <-- *y* from ?previous? connection
Received connection from: 127.0.0.1:49368
Message: Hell
x:5 <-- *x* from current connection
y is missing again.
Any help or suggestions are greatly appreciated!
TCP is a stream oriented protocol. There are no "packets" at the level you are writing code. TCP guarantees that the same bytes you send, will arrive at the destination in the same order. However, there are no message boundaries.
Your code that calls recv() must be prepared to receive fewer bytes than requested, and call recv() again until you get the number of bytes you expect.
Your issue has nothing to do with TCP streaming (though you do have that problem and should fix it per Greg's answer).
Instead, your issue is output buffering -- by default stdout is line buffered, which means that characters written with printf actually go into a buffer and are only output to the screen when a \n (newline) is written to the buffer. So your line:
printf("Message: %s\n x:%d\n y:%d", ...
Will only print up to the last newline (before y), and the y:25 will just be put in the buffer. Later, when you print more stuff that includes a newline, the buffered string will appear along with whatever else you printed. Add a newline after the "y:%d" and it will appear when you expect.
You have two problems:
your server code doesn't have a newline at the end of the second printf, so the output can't be what you show. Either append a newline to that second printf, or use fflush(stdout) after it, to flush the value of y.
as Greg says, you can't rely on receiving entire messages anyway, and should have a loop here.
I'd expect #1 to be your current problem, but you should fix both.
I'm currently writing a server application on Linux x86_64 using <sys/socket.h>.
After accepting a connection via accept(), I use fdopen() to wrap the retrieved socket into a FILE* stream.
Writing to, and reading from, that FILE* stream usually works quite well, but the socket becomes unsusable as soon as I write to it while it has a non-empty read buffer.
For demonstration purposes, I've written some code that listens for a connection, then reads the input, line by line, into a read buffer using fgetc(). If the line is too long to fit into the buffer, it's not completely read, but instead read during the next iteration.
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
FILE* listen_on_port(unsigned short port) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in name;
name.sin_family = AF_INET;
name.sin_port = htons(port);
name.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sock, (struct sockaddr*) &name, sizeof(name)) < 0)
perror("bind failed");
listen(sock, 5);
int newsock = accept(sock, 0, 0);
return fdopen(newsock, "r+");
}
int main(int argc, char** argv) {
int bufsize = 8;
char buf[9];
buf[8] = 0; //ensure null termination
int data;
int size;
//listen on the port specified in argv[1]
FILE* sock = listen_on_port(atoi(argv[1]));
puts("New connection incoming");
while(1) {
//read a single line
for(size = 0; size < bufsize; size++) {
data = fgetc(sock);
if(data == EOF)
break;
if(data == '\n') {
buf[size] = 0;
break;
}
buf[size] = (char) data;
}
//check if the read failed due to an EOF
if(data == EOF) {
perror("EOF: Connection reset by peer");
break;
} else {
printf("Input line: '%s'\n", buf);
}
//try to write ack
if(fputs("ack\n", sock) == EOF)
perror("sending 'ack' failed");
//try to flush
if(fflush(sock) == EOF)
perror("fflush failed");
}
puts("Connection closed");
}
The code should compile in gcc without any special parameters. Run it with the port number as argument and use netcat to connect to it locally.
Now, if you try sending strings that are shorter than 8 characters, this will run flawlessly.
But if you send a string containing more than 10 characters, the program will fail.
This sample input:
ab
cd
abcdefghij
Will create this output:
New connection incoming
Input line: 'ab'
Input line: 'cd'
Input line: 'abcdefgh'
fflush failed: Illegal seek
EOF: Connection reset by peer: Illegal seek
Connection closed
As you see, (rightly) only the first 8 characters of abcdefgh are read, but when the program tries to send the 'ack' string (which the client never receves), and then flush the output buffer, we receive an Illegal seek error, and the next call to fgetc() returns EOF.
If the fflush() part is commented out, the same error still occurs, but the
fflush failed: Illegal seek
line is missing from the server output.
If the fputs(ack) part is commented out, everything seems to work as intended, but a perror() manually called from gdb still reports an 'Illegal seek' error.
If both fputs(ack) and fflush() are commented out, everything does work as intended.
Unfortunately, I've not been able to find any good documentation, nor any Internet discussions on this problem, so your help would be greatly appreciated.
edit
The solution i finally settled for is to not use fdopen() and FILE*, since there seems to be no clean way of converting a socket fd into a FILE* that can reliably used in r+ mode.
Instead, I directly worked on the socket fd, writing my own replacement code for fputs and fprintf.
If anyone needs it, here is the code.
Clearly "r+" (read/write) mode does not work on sockets in this implementation, no doubt because the underlying code assumes that it must do a seek to switch between reading and writing. This is the general case with stdio streams (that you must do some kind of synchronizing operation), because back in the Dim Time, actual stdio implementations had only a single counter per stream, and it was either a counter of "number of characters left to read from stream buffer via getc macro" (in read mode) or "number of characters that can safely be written to stream buffer via putc macro (in write mode). To that that single counter re-set, you had to do a seek-type operation.
Seeks are not allowed on pipes and sockets (since "file offset" is not meaningful there).
One solution is not to wrap a socket with stdio at all. Another, probably easier / better for your purposes, is to wrap it with, not one, but two stdio streams:
FILE *in = fdopen(newsock, "r");
FILE *out = fdopen(newsock, "w");
There's another flaw here though, because when you go to fclose one stream, that closes the other's file descriptor. To work around that, you need to dup the socket descriptor once (in either of the two calls above, it does not matter which one).
If you intend to use select or poll or similar on the socket at some point, you should generally go for the "don't wrap with stdio" solution, since there's no nice clean portable way to track stdio buffering. (There are implementation-specific ways).
Don't use fflush() on network sockets. They are unbuffered streams.
Also, this code:
//read a single line
for(size = 0; size < bufsize; size++) {
data = fgetc(sock);
if(data == EOF)
break;
if(data == '\n') {
buf[size] = 0;
break;
}
buf[size] = (char) data;
}
does not read a single line. It only reads up to the buffer size, which you defined as 8. sock will still have data for you to receive which you should receive before writing to the stream with fputs. BTW you can replace that whole block with
fgets(buf, bufsize, sock);
Yes, you can use one file stream to handle your socket, at least on Linux.
But you should be careful with it: you must only use ferror() to test for errors. I have some code that use this and run flawlessly in production on a major French site.
If you use errno or perror() you'll catch any internal error that the stream will encounter, even if it wants to hide it to you. And "Illegal seek" is one of them.
Also, to test for real EOF conditions, you should use feof(), since when returning true it's mutually exclusive with ferror() returning a non-zero value. It's because, when using fgetc() you don't have any mean to differentiate error from real EOF conditions. So you should probably better use fgets() as another user pointed out.
So, your test:
if(data == EOF) {
perror("EOF: Connection reset by peer");
break;
} else {
printf("Input line: '%s'\n", buf);
}
Should be written as:
int sock_error = ferror(sock);
if (sock_error) {
fprintf(stderr, "Error while reading: %s", strerror(sock_error));
} else {
printf("Input line: '%s'\n", buf);
}
Try this :
#define BUFSIZE 88
FILE* listen_on_port(unsigned short port) {
...
}
int main(int argc, char** argv) {
int bufsize = BUFSIZE;
char buf[ BUFSIZE ];