read() function not allowing anything to be printed after newline character - c

I have a function that reads a file from a server and returns the data:
int readMessageFromServer(int fileDescriptor) {
char buffer[MAXMSG];
int nOfBytes;
nOfBytes = read(fileDescriptor, buffer, MAXMSG);
if(nOfBytes < 0) {
perror("Could not read data from server\n");
exit(EXIT_FAILURE);
}
else
if(nOfBytes == 0)
return(-1);
else
printf("Server Message: %s\n", buffer);
return(0);
}
The problem is with the line
printf("Server Message: %s\n", buffer);
If I change this line to
printf("Server Message: %s\n>", buffer);
It refuses to print the '>' sign until it gets more data.
Is this a known limitation or am I doing something wrong?
I should probably add that the call to this function looks like this:
while(readMessageFromServer(sock) > 0) {continue;};

Besides the fact that you probably wanted to write the > inside the quotes, you'll need to flush the output buffer by calling fflush(stdout). The buffers are usually only flushed after newlines.

nOfBytes = read(fileDescriptor, buffer, MAXMSG);
There is no guarantee how many bytes you read or whether they constitute a null terminated string. At a minimum you should change to something like this:
int readMessageFromServer(int fileDescriptor) {
char buffer[MAXMSG];
int nOfBytes;
nOfBytes = read(fileDescriptor, buffer, MAXMSG - 1);
if(nOfBytes < 0) {
perror("Could not read data from server\n");
exit(EXIT_FAILURE);
}
else
if(nOfBytes == 0)
return(-1);
else
{
buffer[nOfBytes] = '\0';
printf("Server Message: %s\n", buffer);
return(0);
}

printf uses stdout which is a buffered output.
Changing printf with fprintf(stderr, ...) should solve your problem.

Related

Pass data through an anonymous pipe to another program

This is my code I'm trying to use to pass data to the other program.:
static int callWithFile(char* buff) {
int myPipes[2];
if( pipe( myPipes ) < 0 ){
perror("Can't pipe through \n");
exit(13);
}
int pid = fork();
switch(pid){
case 0:
{
if(verbose_flag) printf("pid is %d; pipe fds are.... %d & %d\n", getpid(), myPipes[PIPE_READ], myPipes[PIPE_WRITE]);
//close (myPipes[PIPE_READ]);
write (myPipes[PIPE_WRITE], buff, strlen(buff) + 1);
close (myPipes[PIPE_WRITE]);
char* pipeArg;
if(verbose_flag){
asprintf (&pipeArg, "/proc/%d/fd/%d", getpid(), myPipes[PIPE_READ]);
printf("\n%s\n", pipeArg);
}
asprintf (&pipeArg, "/dev/fd/%d", myPipes[PIPE_READ]);
char* progArgv[] = {
"prog",
"--new_settings",
pipeArg,
//"/dev/fd/0",
NULL
};
// This works just fine
// FILE* fp = fopen(pipeArg, "r");
// if (fp == NULL) {
// perror("Can't open fd pipe file \n");
// exit(14);
// }
// fread(buff, sizeof(char), strlen(buff) + 1, fp);
// printf("buff: %s", buff);
execvp(prog_path, progArgv);
perror("execvp screwed up");
exit(15);
}
case -1:
perror("fork screwed up ");
exit(16);
}
close (myPipes[PIPE_READ]);
close (myPipes[PIPE_WRITE]);
wait(NULL);
puts("done");
}
In all aspects, the code appears to be correct and providing the file descriptor for the other program to read from.
However, for some reason, the other program tells it can't open and read the file.
This is the program that reads the data: https://github.com/tuxedocomputers/tuxedo-control-center/blob/master/src/common/classes/ConfigHandler.ts#L87
It complains: Error on read option --new_settings with path: /dev/fd/4
I already confirmed that it is correct JSON, so that shouldn't be the problem.
As for debugging it, I can't make it run on my machine for some reason.
Cannot launch program because corresponding JavaScript cannot be found..
My objective is to have the equivalent of this in bash:
program <(echo $buff)
Where $buff is the contents of the buff function argument.
Everything in your code is correct except this:
write (myPipes[PIPE_WRITE], buff, strlen(buff) + 1);
See that + 1? That's the failure. You are sending a null byte (AKA character 0 or '\0') to the program when its JSON parser doesn't expect it.
Try this instead (without the + 1):
write (myPipes[PIPE_WRITE], buff, strlen(buff));

Copy data from file X to file Y program in C

I tried to write basic program in C which copy data from file to another with given source path, destination path and buffer size as input.
my problem is the destination file filled with junk or something because its way larger than the source (get bigger depending on buffer size) and can't be open.
How do i read and write just the bytes in the source?
i'm working in linux, and this is the actually copying part:
char buffer[buffer_size];
int readable=1;
int writeable;
while(readable != 0){
readable = read(sourcef, buffer, buffer_size);
if(readable == -1){
close(sourcef);
close(destf);
exit_with_usage("Could not read.");
}
writeable = write(destf, buffer, buffer_size);
if(writeable == -1){
close(sourcef);
close(destf);
exit_with_usage("Could not write.");
}
}
writeable = write(destf, buffer, buffer_size);
must be
writeable = write(destf, buffer, readable);
Currently you do not write the number of characters you read but all the buffer, so the output file is too large
You also manage wrongly the end of the input file
The return value of read is :
On success, the number of bytes read is returned (zero indicates end of file)
On error, -1 is returned
A proposal :
/* you already check input and output file was open with success */
char buffer[buffer_size];
for(;;){
ssize_t readable = read(sourcef, buffer, buffer_size);
if(readable <= 0){
close(sourcef);
close(destf);
if (readable != 0)
/* not EOF */
exit_with_usage("Could not read.");
/* EOF */
break;
}
if (write(destf, buffer, n) != n) {
close(sourcef);
close(destf);
exit_with_usage("Could not write.");
}
}
I suppose exit_with_usage calls exit() so does not return
Note in theory write may write less than the expected number of characters without being an error, and the write has to be done in a loop, but in that case it is useless to manage that
read function returns how many bytes were read to buffer(which has buffer_size). Its not always the case actual bytes read has same value as buffer size(consider scenario if there are not enough bytes left in source file to fully fill your buffer). So you should write to destination file not buffer_size(third argument of the write function), but how many bytes have you read - that is readable variable in your code
You should exit when readable returns an error.So
while(readable != 0){
should be
while(readable != -1){
So that loop could be terminataed when an readfile is exhausted.
You see currently after the whole readfile has been read, calling read fails but write is being called repeatedly since execution has no exit path for failure on read. Also write should only write the number of bytes read. So the code would look like this:
char buffer[buffer_size];
int readable=1;
int writeable;
while(readable != -1){
readable = read(sourcef, buffer, buffer_size);
if(readable == -1){
close(sourcef);
close(destf);
exit_with_usage("Could not read.");
}
writeable = write(destf, buffer, readable);
if(writeable == -1){
close(sourcef);
close(destf);
exit_with_usage("Could not write.");
}
}
Simple code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // For system calls write, read e close
#include <fcntl.h>
#define BUFFER_SIZE 4096
int main(int argc, char* argv[]) {
if (argc != 3) {
printf("Usage %s Src_file Dest_file\n", argv[0]);
exit(1);
}
unsigned char buffer[BUFFER_SIZE] = {0};
ssize_t ReadByte = 0;
int src_fd, dst_fd;
// open file in read mode
if ((src_fd = open(argv[1], O_RDONLY)) == -1) {
printf("Failed to open input file %s\n", argv[1]);
exit(1);
}
// open file in write mode and already exists to overwrite
if ((dst_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 644)) == -1) {
printf("Failed to create output file %s\n", argv[2]);
exit(1);
}
// loop
while (1) {
// read buffer
ReadByte = read(src_fd, buffer, sizeof(buffer));
// error with reading
if (ReadByte == -1) {
printf("Encountered an error\n");
break;
} else if (ReadByte == 0) {
// file end exit loop
printf("File copying successful.\n");
break;
}
// error with writing
if (write(dst_fd, buffer, ReadByte) == -1) {
printf("Failed to copying file\n");
break;
}
}
// Close file
close(src_fd);
close(dst_fd);
exit(0);
}
Run
./program src_file dest_file

C sockets: why is my server appending extra characters in the end?

I am writing a simple server/client socket in C. The client asks the user to input a message and the server responds by repeating the same. The problem is when I send a message from the client the server responds back by appending extra character. How do I fix this.
This is my Client code
while(1) {
bzero(buffer, BUFSIZE);
printf("Enter Message: ");
scanf("%s", buffer);
//send some data
if(send(socket_fd, buffer, strlen(buffer), 0) <0) {
fprintf(stderr,"sending failed\n");
return 1;
}
//receive a reply from the server
if(recv(socket_fd, server_reply, BUFSIZE,0)<0)
{
fprintf(stderr,"failed to reply. \n");
break;
}
fprintf(stdout, "Reply: %s\n ", servreply);
}
This is my server code
int read_size;
while((read_size = recv(client_socket_fd, buffer, BUFSIZE,0))>0)
{
// Reply back to the client
if (0 > write(client_socket_fd, buffer, strlen(buffer))) {
fprintf(stderr, "could not write back to socket\n");
} else {
fprintf(stdout, "message back to client\n");
}
}
if(read_size==0)
{
fprintf(stderr,"disconnected.\n");
fflush(stdout);
}
else if(read_size==-1){
fprintf(stderr, "error.\n");
}
This is the output
Enter Message: welcome
Reply: welcome
Enter Message: hello
Reply: hellome
Enter Message: hi
Reply: hillome
You need a string in order to use strlen(). Your arrays are not strings, rely on read_size instead for the length of the buffer.
Strings in c are just a sequence of printable characters followed by a '\0', and none of your arrays has any '\0' so strlen() is causing undefined behavior. The strlen() function actually scans the string until it finds the '\0' and in the process it counts how many characters were there.
#Iharob's answer is correct. Basically, change the line:
write(client_socket_fd, buffer, strlen(buffer))
to:
write(client_socket_fd, buffer, read_size)
It isn't. You are printing junk at the end of your buffer. You're also ignoring end of stream.
if(recv(socket_fd, server_reply, BUFSIZE,0)<0) {
fprintf(stderr,"failed to reply. \n");
break;
}
fprintf(stdout, "Reply: %s\n ", servreply);
should be
int count;
if((count = recv(socket_fd, server_reply, BUFSIZE,0))<0) {
fprintf(stderr,"failed to reply. \n");
break;
}
else if (count == 0) {
// EOS
fprintf(stderr, "peer has disconnected.\n");
break;
} else {
fprintf(stdout, "Reply: %.*s\n ", count, servreply);
}
Your 'write back to the client' is also incorrect:
if (0 > write(client_socket_fd, buffer, strlen(buffer))) {
should be
if (0 > write(client_socket_fd, buffer, read_size)) {

Read Posix System Call

I'm trying to print out the contents of a file, however the program will pause at the read() function and won't continue until I hit the enter key. Once the enter key is pressed, nothing is printed to the terminal. The rest of the program is not shown, but here is the method that is causing the issue.
{
char buff[1024];
ssize_t bytesRead = 0;
int readFile, error;
if((readFile = open(file,O_RDONLY)<0))
{
printf("can't open %s\n",file);
error = errno;
return -1;
}
do{
memset(buff,0,1024);
if((bytesRead=read(readFile,buff,1024))==-1)
{
printf("error reading file");
error = errno;
printf("%d",error);
}
else
printf("%s",buff);
}while(bytesRead==1024);
printf("\n");
close(readFile);
return 1;
}
Alternatively, if I change the read() function to pread(file,buff,1024,0) it throws an illegal seek 29 error.
Hitting the enter key should not effect the read call unless you are reading from stdin (standard input). In that case, the input you provided - whitespace - may be printed out in the printf("%s", buff); call. If you could include some steps on how you found out that this is the method causing the issue or how you found out that it pauses at the read line (and if you are reading from /dev/stdin), it may be easier to help.
Consequently, the same printf call may never return, if the bytes read do not contain a null and the bytesRead count is 1024 - the string in buff would not be null terminated. You can fix this by either doing buff[1023] = '\0'; or by setting a length limit in the printf call like printf("%.1024s", buff);
do{
memset(buff,0,1024);
if((bytesRead=read(readFile,buff,1024))==-1)
{
printf("error reading file");
error = errno;
printf("%d",error);
}
else
printf("%s",buff);
}while(bytesRead==1024);
Your loop isn't correct. It assumes that read() fills the buffer; it fails if the file isn't a multiple of 1024 bytes; it corrupts errno before printing it; and it does unnecessary memset() operations. Honey it's a mess. It should look like this:
while ((bytesRead=read(readFile, buff, sizeof buff)) > 0)
{
printf("%.*s", bytesRead, buff);
}
if (bytesRead < 0)
{
error = errno;
perror("error reading file");
printf("errno=%d\n",error);
}

C: printf non printing \n

In C, I ask the server to print the content of any messages that it receives. All messages follow the format: "Message: /counter/".
while (1){
length = sizeof(struct sockaddr);
/* receive from client */
lenstr = recv(newfd, buff, 20000, 0);
if (lenstr == -1){
perror("recv(): ");
exit(1);
}
buff[lenstr] = '\0';
printf("Received: %s \n", buff);
/* send back to client*/
if (send(newfd, buff, lenstr, 0) < 0){
perror("send(): ");
exit(-1);
}
When I run the server, messages appear one after the other, without going to the new line. What am I missing here? (connection is TCP here)
Thanks.
The data it receives from the socket may contain zeroes or control characters. These should not be printed.
Try using the following function to dump received data into stdout. It replaces all non-printable characters with a dot:
void dump_buf(char const* buf, size_t buf_len) {
char const* buf_end = buf + buf_len;
while(buf != buf_end) {
char c = *buf++;
putchar(isprint(c) ? c : '.');
}
putchar('\n');
}
// ...
lenstr = recv(newfd, buff, 20000, 0);
if (lenstr == -1) {
perror("recv(): ");
exit(1);
}
dump_buf(buff, lenstr);
TCP doesn't have "messages", it handles continuous byte streams in both directions. You are just reading whatever is less between the received data up to that instant and your 2000. Perhaps you really want Stream Control Transmission Protocol? Or mark message ends in some way (perhaps by '\n'), and read character by character? Or just read the length of a single message (if they are fixed length, that is)?

Resources