Hi I am trying to implement TCP socket stream. I have a buffer of size 12, and I am reading into this buffer in a loop.
I expected the read operation to add onto the buffer with each read call until the buffer is full, but instead, it starts from the beginning of the buffer, overwriting what is already in there on each iteration.
How can I append to the buffer with each read, so that the previous bytes are preserved?
void *th_read(void *arg)
{
reader_arg_t *rArg = (reader_arg_t *)arg;
int buf_size = 12;
int bytes_recevied, rv;
char buf[buf_size];
while (1)
{
rv = 0;
bytes_recevied = rv;
memset(buf, 0, buf_size);
socket_context_t ctx;
tsq_dequeue(rArg->reader_queue, &ctx);
printf("reading from socket: %i\n", ctx.sockfd);
while (1)
{
rv = read(ctx.sockfd, buf, buf_size - bytes_recevied);
if (rv < 1)
break;
bytes_recevied += rv;
printf("bytes_recevied: %i\nbuf: %s\n", bytes_recevied, buf);
}
perror("read");
close(ctx.sockfd);
printf("%s\n", buf);
}
}
When I connect with telnet and write 2 times separates by pressing enter, I get this output. Writing hello the first time and the digit 1 the second time.
reading from socket: 5
bytes_recevied: 7
buf: hello
bytes_recevied: 10
buf: 1
lo
I want the buffer to contain hello1 instead of 1\rlo.
I found a question that showed the zero byte thing but its not useful for my use case unless I would maybe use a second buffer and add on each read the stuff from the first buffer until the zero byte.
reading buffer from socket
You should send new position of buffer into read function.
rv = read(ctx.sockfd, buf + bytes_received, buf_size - bytes_recevied);
Related
I am trying to write a program that will read up to N bytes at a time from a file, store that in a buffer, and send that buffer to a server. This will repeat until all bytes have been read.
My problem is that it successfully sends the first N bytes, but for the remaining X bytes it overwrites up to X bytes of the original N bytes and sends that along to the server, so that the total bytes received at the end of the program are 2*N instead of N+X.
For example if I have a message and reads N bytes (in this example reads the first three lines):
1
2
3
4
The message received by the server is:
1
2
3
4
2
3
Any help as to why this is happening is appreciated!
Relevant client code:
// send data
ssize_t remaining;
char buffer[SEND_BUFFER_SIZE];
int count = 1;
// do this if there are still bytes to read
while(read(0, buffer, sizeof(buffer)) > 0) {
printf("%s\n", buffer);
// count = read(0, buffer, sizeof(buffer));
send(sock, buffer, sizeof(buffer), 0);
// char buffer[SEND_BUFFER_SIZE];
}
// close socket
close(sock);
Relevant server code:
// receive message
char buffer[RECV_BUFFER_SIZE];
int recv_bytes = RECV_BUFFER_SIZE;
int i = 1;
int count;
// while (1 != 2) {
while(recv_bytes != 1) {
recv_bytes = recv(sock, buffer, RECV_BUFFER_SIZE, 0);
fwrite(buffer, recv_bytes, 1, stdout);
fflush(stdout);
if (recv_bytes < RECV_BUFFER_SIZE) {
break;
}
}
I have this code for verify what's in the array buffer, but i'm always getting different values on array and it makes my program getting a 56( 8 on ascii) when its not supose too, can somebody helps ?
This sends a buffer for socket to be read on file 1:
void send_stream(char buff[], int sockfdes)
{
if (write(sockfdes, buff, strlen(buff) + 1) == -1) {
perror("ERROR: envia_stream: simulador");
}
}
void prepare_message(int tipo, int id)
{
char buff[3];
buff[1] = id;
switch (tipo)
{
case CRIACAO_P:
buff[0] = '1';
//buff[2] = tempo; //HORA
send_stream(buff, sockfd);
break;
}
this file 2 read from socket and put in buffer:
char buffer[5];
while(1)
{
read(novosockfd, buffer, sizeof(buffer));
if (buffer[0] == '8')//FIM
{
printf("Buffer[0]: %d \n", buffer[0]);
printf("Buffer[1]: %d \n", buffer[1]);
printf("Buffer[2]: %d \n", buffer[2]);
printf("Buffer[3]: %d \n", buffer[3]);
printf("Buffer[4]: %d \n", buffer[4]);
printf("\nSimulação terminou\n");
break;
}
}
}
firstly you should tell us from where are you reading from, if you are reading from a socket, trying to implement a server or are you reading from a local socket?
Also, you should also check for the return type, like this:
if ( (read(novosockfd, buffer, sizeof(buffer)) <= 0 ) {
perror("error in read");
} else
{
//code to run if the read did not failed;
}
Note that for perror to work you have to #include
perror will automatically print the message in "" followed by the error description in the console. After you do all this, come and tell us more details.
Take not that if you do not check for failure in read, your code continues to get executed.
Judging by your update, you are first writing a buffer of size 4 bytes and reading for a buffer of 5 bytes, note that reading from a socket blocks until receiving the specified size in buffer, hence if you send 4 bytes to that socket, you can't expect to be able to read 5 bytes. So in order to be able to send the message, you should have char buff[4] declared in preare_message() instead of char buff[3], and also the parameter for the size of the message in the method write(int fildes, const void *buf, size_t nbytes) is of type size_t, so you should use : write(sockfdes, buff, sizeof(char) * strlen(buffer) + 1);
And you are also assigning id(int) into a char buffer.
I have to create a program that asks from standard input a string and write in standard error the string previously written.
This is my program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main() {
char *buffer = malloc(sizeof(char)*20);
int len = 0;
do {
len = read(STDIN_FILENO, buffer, 20);
if(len == -1)
write(STDERR_FILENO, "Error read\n", 10);
else
write(STDERR_FILENO, buffer, len);
} while(strncmp(buffer,"fine\n", 5));
free(buffer);
return 0;
}
The code works but I'm not satisfied..there is one problem:
The buffer is a 20char but I can insert more than 20 char...why? How I can limit the buffer to only 20 char?
The code works but I'm not satisfied..there is one problem: The buffer is a 20char but I can insert more than 20 char...why?
Because your program can't stop someone inputting more than 20 chars; all it can do is limit that it doesn't overflow the buffer which it already does - read() doesn't read more than the requested bytes. It only appears as if a read() call is reading more than size (20) but acutally read() reads only (upto) 20 chars and the rest is read in the next iteration.
No matter what method you use to read input and/or increase buffer size, this problem of "extra input" is always going to be there.
What you can do instead is check if if len is 20 and buffer[19] is not \n:
else {
write(STDERR_FILENO, buffer, len);
/* Read out the left over chars. */
if (len == 20 && buffer[19] != '\n') {
char c;
do {
read(STDIN_FILENO, &c, 1); /* left out the error checking */
} while (c != '\n');
}
Or increase the buffer size, say, to 512 bytes and then only look at the first 20 bytes that you're interested in.
Note: Add error checking for all read() and write() calls.
You're not allocating enough memory for your buffer. You always need 1 more to store the NUL terminating character. And you also need to remember to add that NUL character to the end of the string read in by read as it won't do it for you.
When you get an error, you should exit the loop.
#define BUF_SIZE (20)
int main() {
char *buffer = malloc(sizeof(char)*(BUF_SIZE+1));
int len = 0;
do {
len = read(STDIN_FILENO, buffer, BUF_SIZE);
if(len == -1) {
write(STDERR_FILENO, "Error read\n", 10);
break;
} else {
buffer[len]='\0';
write(STDERR_FILENO, buffer, len);
}
} while(strncmp(buffer,"fine\n", 5));
free(buffer);
return 0;
}
You'll probably also find that the strncmp(buffer,"fine\n", 5) isn't going to work as you'd need to process the read in string to handle lines of input as read will happily read in multiple lines at a time (assuming they all fit in the buffer size).
My code is too long to post all here so i'm going to sum up what's wrong.
In a server part i'm sending on a socket 3 things :
A message
The content of a file
Another message
In a client part i'm receiving these things but :
This first is to print on terminal
The second to write in a new file
The last to print on the terminal too
But my client is stuck on a read and i really don't know why. I'm on the problem for hour so if someone can help me, it will be very great !
edit : Basically, i think my problem is that i don't know what to write on the server to stop the read on the client.. Is it \n, \0.. ?
Here's the 2 part of code :
server
void send_content(t_server *s, FILE *fd, int rfd)
{
int len;
char *buff;
write(s->socket, "150 File status okay;" \
"about to open data connection.\n\0", strlen("150 File status okay;about to open data connection.\n\0"));
fseek(fd, 0, SEEK_END);
len = ftell(fd);
buff = malloc(len * sizeof(char));
read(rfd, buff, len);
write(s->socket, buff, len);
write(s->socket, "\n\0", strlen("\n\0"));
write(s->socket, "226 Closing data connection.\n\0", strlen("226 Closing data connection.\n\0"));
free(buff);
}
client
void getfile(t_client *c, char **tab)
{
int ret;
int fd;
int z;
char buff[4096];
z = 0;
read(c->fd, buff, 4096);
write(1, buff, strlen(buff));
if (strlen(buff) < 25)
return ;
fd = creat(tab[1], S_IRUSR | S_IWUSR);
while (z == 0 && (ret = read(c->fd, buff, 4096)) > 0)
{
if (ret < 4096)
z = -1;
write(fd, buff, strlen(buff));
memset(buff, '\0', 4096);
}
read(c->fd, buff, 4096); // Stuck here
write(1, buff, strlen(buff));
close(fd);
}
Like noted you need a read function like this to make sure you receive
specified number of bytes(this function will loop till it receives number of bytes it was told to). Just use this receivall method instead of read everywhere.
With files you typically first send the file length, and then receive the file.
I did something similar while ago, hope it will help you a bit. This is the client side, which tries to receive first file length from the server, then the file:
/* create file */
FILE * ptrMyFile = fopen(&filenames[i][0],"wb");
if(NULL == ptrMyFile)
{
printf("Unable to open file \n");
return 1;
}
int size = 0;
int t = 4;
/* first receive file size from server */
/* NOTE: error checking is omitted from code, nevertheless users should stil do some error checking when using this code */
readall(sockfd, (unsigned char*) &size, &t);
/* how many 256 byte chunks are there? */
int div = size / 256;
/* loop to receive each chunk. */
for(int k = 0; k < div; k++)
{
int chunk_size = 256;
/* make sure we receive 256 bytes */
readall(sockfd, buffer, &chunk_size);
/* write to file */
fwrite(buffer, chunk_size, 1, ptrMyFile);
}
/* read the final chunk. */
int whatsleft = size - 256 * div;
readall(sockfd, buffer, &whatsleft);
/* write */
fwrite(buffer, whatsleft, 1, ptrMyFile);
/* close file */
fclose(ptrMyFile);
I leave the server part to you.
char buff[4096];
z = 0;
read(c->fd, buff, 4096);
write(1, buff, strlen(buff));
You should be saving the return value of the call to read(), in order to find out how many bytes you just received. You may have to make several calls to read() in order to get the entire message. It's wrong to use strlen() to find out how many bytes were received, because the buffer contents are uninitialized, and the first chunk of the message could be cut off anywhere, so you can't count on it being null-terminated.
I'm trying to write an experimental client / server program to prove whether the write fails or blocks when the send buffer is full.
Basically, I have an infinite loop on the sender program where I use select() to check if I can write on the buffer (which, I think means that the socket buffer isn't full), if I can write on the buffer than I write() a character. The loop breaks when FD_ISSET(sockfd, &writefds) is false (I can't write on the buffer because it's full).
The reciever program is sleeping for one minute before starting to read(). I expect the sender to fill the buffer within this sleeping time but in fect, the programs never end.
sender:
int main(int argc, char *argv[]) {
char buffer[100];
int sockfd, total = 0, bytes = 0;
fd_set writefds;
sockfd = dial(argv[1], argv[2]);
bzero(buffer, sizeof buffer);
while(1)
{
int ret = 0;
FD_ZERO(&writefds);
FD_SET(sockfd, &writefds);
if((ret = select(sockfd + 1, NULL, &writefds, NULL, 0)) < 0)
{
perror("select");
exit(errno);
}
if(FD_ISSET(sockfd, &writefds))
{
write(sockfd, "a", 1);
total++;
continue;
}
else
{
puts("I can't write in the socket buffer");
break;
}
}
printf("nb chars written: %d\n", total);
return 0;
}
reciever:
int foo(int sockfd) {
char buffer[100];
int t, total = 0;
bzero(buffer, sizeof buffer);
printf("I have a new client\n");
sleep(60);
while((t = read(sockfd, buffer, sizeof buffer)) > 0)
{
total += t;
printf("%d ", total);
}
printf("nb chars read: %d\n", total);
if(t < 0)
{
perror("read");
}
printf("I don't have that client anymore\n");
return 0;
}
Your select timeout is null, so select() will block when the send buffer is full. This means when it returns, the socket is writable, and you'll never get to your code "I can't write in the socket buffer".
See man page http://linux.die.net/man/2/select
If you want a zero timeout, i.e. don't block on select(), you need to pass a pointer to a timeval structure with both fields set to zero.
You're on the right track, but the socket send buffer could be 48k or more. That's a lot of iterations. Try writing 8k at a time, not just one byte. And increase the time before the receiver reads.
NB No real need to test this. It blocks in blocking mode, and fails with EAGAIN/EWOULDBLOCK in non-blocking mode. See the man page.