I'm so lost. I can't figure out how to stop reading from the server. I'm basically sending a list of every file in the directory from the server to the client. Heres what I'm doing.
SERVER SIDE:
struct dirent *ep = readdir(dp);
while( ep ){
sprintf(buf, "%s", (ep->d_name));
n = write(newsock, buf, MAX );
ep = readdir(dp);
}
CLIENT SIDE:
while( n = read(sock, buf, MAX)){
printf("buf: %s\n" , buf);
}
So the server side stuff works fine. I can see I'm sending all the file names right, but on the client side it reads all the names but just sits waiting to read more.
You either need to send some "EOF" indicator from the server so the client knows to break the loop, or have the server close the socket (after allowing 'some time' for the client to read all the data). This will cause the read to exit with an error condition.
Second is easier on the face of it, first is likely to be more reliable and efficient. Congratulations, you have now built your first communications protocol.
Define a protocol.
A very simple one might be to let the server send an empty (0-length) file name to the client to tell the client that it's done with sending. To successfully do so you might like to delimit each file name by for example an addtionaly \r\n sequence, or similar.
Related
New to Socket Programming. I was making a HTTP server. In the persistent connection, I keep the socket open after the server has sent the first file (1 MB text file) for the 1st HTTP request from the client. After that the server and client programs just sit idle. I have searched a lot and found that recv() keeps looking for data on the socket until the socket connection closes from the server side.
What Should I do in case of a persistent connection?
I am reading a file at the client side (File contains many lines. On each line there's just a file name, that is to be fetched from the server via a persistent connection)
Part of Server code which send the file requested:
while((bytesread = fread(filecontent,sizeof(char), 1024, fp))>0)
{
printf("Bytes Read:%d File Content:%s\n",bytesread,filecontent);
if((n = send(*newsockfd, filecontent, 1024,0))<0)
{
error("SERVER Error: Failed to Write File to Socket");
break;
}
bzero(filecontent,1024);
}
Part of client code where I read the file that has been sent by the server:
for(;;)
{
n=recv(socketfd, buffer, 1024,0);
printf("%d\n",n);
if(n>0)
{ printf("\n in while for reading the file for n bytes %d \n",n);
printf("Response:\n%s",buffer);
}
else if(n<0)
{
disperror("Error reading from socket");
}
if(n==0)
break;
}
Have spent a lot of time. Could not get what to do...
Your client-server protocol is insufficient. The server sends all the bytes of the input file (and more, because you hard-coded 1024 instead of using bytesread). But how should the client understand when the file is complete?
One easy solution is to have the server begin each transmission with the file size. You can simply send a uint64_t (not int because it must be a fixed size on all platforms). That number will represent the total bytes to follow (i.e. the file size). You can get the file size using fseek in the usual way (SEEK_END then ftell or similar).
Then, once your client has received the specified number of bytes, it can break out of the loop.
continues reading even though socket is empty
'Socket is empty' is meaningless. It is either open or closed. In this case it is still open, so your code keeps reading. It will only stop when the peer closes the connection.
If you're going to implement HTTP you need a good working knowledge of RFC 2616, especially the parts relating to content length. Your code doesn't begin to address that currently, and it's too brodpad a topic to cover here. Uffice it to say that keepalive and reading a socket to end of stream are mutually inconsistent.
NB if you get an error reading a socket other than EAGAIN/EWOULDBLOCK you should exit the loop, and you should also print the real error, not some message of your own devising.
NB (2) You don't need to zero the buffer.
NB (3) The correct way to print the buffer is printf("%.*s", n, buffer), but only if n > 0.
I am a C newbie learning sockets. I wrote a client-server program to receive a file and write it to another file.
The program itself works fine - the file is read by server properly and the client receives it in full, but the client does not exit after receiving all the data.
How would the client know when the entire file is received and how do I make it exit? Following is my client snippet.
Note: I added the condition while (data > 0) as a part of this attempt. Please correct this if wrong.
#define BUFFER 2048
char recived_data[BUFFER];
bzero(recived_data, BUFFER);
FILE *new_file = fopen(“Test.jpg”, “w”);
int data;
do {
data = recv(sockfd, recived_data, BUFFER, 0);
fwrite(recived_data, 1, sizeof(recived_data), new_file);
} while (data > 0);
Your server should close the socket after the whole file content has been sent. This would cause your recv function to return zero and end the client's receive loop.
If you want to keep the connection for some reason, then you would need to send some additional information to the client first (e.g. file length) - so the client knows when one file ends and (potentially) another begins. I'm not sure if you are interested in that, though.
The sender can send the file size before sending the file. The receiver can then receive the file size (say 4 bytes), then call recv() until the full file size has been received.
i have made one client server application in which client sends file (i.e ODT,PDF,MP3,MP4, etc) and server receives file.
i am dividing file in chunks and then transmits them in while loop.
below i have given main logic for both client and server.
when i do loop-back with 127.0.0.1, this code works successfully.
but when i runs client and server on two different PC, after transmitting a file client exits but server keeps receiving and then i have to press ctrl^C. the size of file at server side reaches over 1GB even if file size at client side is only around 4.2 MB.
and in loopback i am not getting such problem.
please tell me the needed corrections.
client.c
#define SIZE 512 // or anything else
char sendbuff[SIZE];
FILE *fr;
fr = fopen("1.mp3","r");
while(!feof(fr)){
count = fread(sendbuff, SIZE,1,fr);
count = send(clientsd, sendbuff,SIZE,0); //clientsd is socket descriptor.
}
send(clientsd, "xyz", 3, 0); //sending '1'. tells server, transmission is over now.
close(fr);
server.c
#define SIZE 512 // same as client side
char recvbuff[SIZE];
FILE *fw;
fw = fopen("2.mp3","w");
while(1){
count = recv(connsd, recvbuff, SIZE,0);
if(!strcmp(recvbuff,"xyz"))
break;
fwrite(recvbuff,SIZE, 1, fw);
memset(recvbuff,0,SIZE);
}
printf("Exit while\n");
fclose(fw);
any other simple and efficient way to do this ?
NOTE : I have changed my question. here some answers are on my old question where i have transmitted "1" instead of "xyz". which was an error.
The most obvious problem is your stop condition on the server side.
You assume that if the first byte received is '1' (0x31) than the transfer is over, but it might be a byte of the data (if the first byte of the chunk in the file is actually '1'). So you need some other way to signal the end of the file. One possibility is to use a wrapping for each packet sent, for example, before each packet send a specific value (for example '1') followed by the length, and when the transfer is complete send '0' to signal that the transfer is completed.
The other problems I can see are that:
You open the files as read text ("r") and write text ("w") which will stop processing if the EOF sequence appears in the middle of the file, instead you need to open them as read/write binary ("rb" / "wb" respectively).
You use chunks of 512 bytes, what if the file is not a multiple of 512 bytes?
I am trying to make a TCP file transferconnection that enables the client to choose what "task" he wants to do (list files in directory, upload, download a file), but not terminate once he makes a choice. Meaning he can do more than one choice per session.
The problem I have is that in my implementation of the while loop on the server side:
while(n= read(sd,rbuf,BUFLEN)){
if (rbuf[0] == 'R'){//CHANGE DIR
//char *dircha;
//read(sd, rbuf, BUFLEN);
printf("ENTER change directory\n");
//chdir(dircha);// this will change directory
}
if(rbuf[0] == 'L'){//LIST FILES
requiem[0] = 'I';
requiem[1] = 20;
printf("TYPE: %c", requiem[0]);
write(sd, requiem , 2);.... //rest of code
The rbuf doesnt get "cleared" and still contains the characters the client made when he typed his choices, and once it enters the while loop and picks a choice, it will never be able to choose another task because rbuf[0] will never be equal to any of the choices i made.
What can I do to make it so that the user can make multiple choices? Thank you so much!
while(n= read(sd,rbuf,BUFLEN)){
is not a good way for implementing your protocol. There is no guarantee that it returns exactly one dataset. E.g. it is possible that:
the read() returns data from two or more write(), or that
the read() returns only partial data from a write()
You should implement either some buffering or a better encoding of your data (e.g. prefix always the type or the length of following data).
Let me start out by saying that this is a homework assignment for an operating systems class and I am not a programmer, especially not in C. I've been at this for a week now and I am simply stuck and I need help. I have to create TCP client and server applications where linux commands are typed into the client, executed on the server and the output is redirected back to the client. I understand the concept and I have it 90+% working. Commands like "ls", "ls -lpq", "cat somefile", "man somecommand" all work fine. Where I run into trouble is with commands that do not return any information like "mkdir newdir" (if the directory already exists it works fine because I get a response). This is all new to me but it seems to me that my problem is with the servers recv command blocking because there is no information to receive. I don't know how to get past this, I have been working this one issue for a week. I'm running out of time and I also have to implement file upload and download and I don't know where to begin there but I can't even start to work on that until I get past this issue.
Thanks
// this is where I think the problem is
while ((rcvd_bytes = recv(sock_fd, recv_str, sizeof(recv_str), 0)) > 0 ) {
// Zero out the inputCopy buffer
memset(&inputCopy, 0, sizeof(inputCopy)+1);
// Copy the recv_str into a new string so that
// we can work with it.
strcpy(inputCopy, recv_str);
argcount = parsecommand(inputCopy, args);
//Send the message back to client
dup2(sock_fd, 1);
if((status = forkAndExecute(args)) != 0) {
//printf("Command %s returned %d.\n", args[0], status);
}
// as a test is I uncomment the following line mkdir newdir
// returns but the following commands are messed up - as I expect.
//printf("\n");
memset(&recv_str, 0, sizeof(recv_str)+1);
fflush(stdout);
}
if(rcvd_bytes == 0) {
puts("Client disconnected");
fflush(stdout);
}
else if(rcvd_bytes == -1) {
perror("recv failed");
exit(0);
}
Sounds like you need to use select .
if(select(fdmax+1, &my_fdset, 0, 0, NULL) > 0) // there is data available to be read
recv(...)
where fdmax is the largest file descriptor (select wants that +1) and my_fdset is a file descriptor set that you add file descriptors to using FD_SET(sockfd, &my_fdset);.
This will only receive when there is data available. Hope that helps.
EDIT :
I asked a similar question when I was writing a simple client/server program to send/recv strings over a TCP socket. I posted the code that I ended up using on that thread here. Mine is different in that I wanted one program to send and recv but if you look at my sender or receiver functions, you may be able to adapt something to make your program do what you want.
Given your problem description, my suspicion is the client code rather than the server code -- or, actually, the protocol you've implicitly created between the two.
It looks like you're just sending the output of the command directly back to the client by using dup2 to point standard output at the socket. Presumably, the client then reads from the socket to get the output from the command? What does the client do when it sends a command to the server and then gets no reply? A command like mkdir will send nothing back. Is it waiting forever for the server to send command output?
In general, for a synchronous client/server protocol (one where the client sends a command and the server sends a response before the client sends another command), you have to agree on a protocol between the client and the server to clearly indicate when the server is done sending data back and the client should send its next command. You may need to add some way for the server to tell the client that the command completed but sent no output.