I need bit clarification on using multiple send/recv in socket programs.
My client program looks below(Using TCP SOCK_STREAM).
send(sockfd,"Messgfromlient",15,0);
send(sockfd,"cli1",5,0);
send(sockfd,"cli2",5,0);
send(sockfd,"cli3",5,0);
send(sockfd,"cli4",5,0);
send(sockfd,"cli5",5,0);
and the server program looks like below.
recv(newsockfd,buf,20,0);
printf("Buffer is %s\n",buf);
when i execute the above program, the output is as below:
Client Msg :Messgfromlient
I believe that the buf size is 20, so only one buffer is getting received.
Adding one more recv on server side.
char buf[20],buf[20];
------skipped------
recv(newsockfd,buf,20,0);
recv(newsockfd,buf1,20,0);
printf("Client Msg :%s\n",buf);
printf("Client Msg :%s \n",buf1);
output:
1st trial:
Client Msg :Messgfromlient
Client Msg :cli2
2nd trail:
Client Msg :Messgfromlient
Client Msg :cli1
As we can see that there is some contradiction in the ouputs,
From client side it looks all the msgs are getting sent, but in server, msg will be received based on buf size,here eventhough buf1 has size of 20, why 'cli3''cli4''cli4' msgs are not getting received on buf1?. Is there any specific limit is there? Please clarify on this.
Thanks in Advance,
Raja
TCP is a byte stream based protocol, it knows nothing about messages. You send 25 bytes in total, and each recv on the other side will read some of those bytes. You can get 20, you might get 1 and then 19 in the next read, you might get 5 then 4 then 11 then 5. The size parameter to recv is the maximum number to read.
You need to loop until you read the whole message yourself, and also understand you might receive more than one "send" in the same received message.
the server program looks like below.
recv(newsockfd,buf,20,0);
printf("Buffer is %s\n",buf);
This is already wrong. It should be:
int count = recv(newsockfd,buf,20,0);
if (count == -1)
{
perror("recv"); // please improve this message
close(newsocketfd);
}
else if (count == 0)
{
// peer has closed the connection
close(newsockfd);
}
else
{
printf("Buffer is %.*s\n",count,buf);
}
This should give you enough of a hint ...
You've got 2 issues:
When you're displaying the results, you're going to stop at the first null byte, which is always after "Messgfromlient". There may be more text already received, but you're not displaying it.
The second issue is that the TCP connection is a stream. You may receive all the data in one go, you may receive only the first byte. You don't know which one is it and can't predict it. You need to handle incomplete reads in your application and you have to handle retries.
You can however make it more likely that all the data will be sent in one packet rather than 6. Have a look at the TCP_CORK option.
Related
I'm trying to get a server to receive messages from a client in TCP.
The problem is, I only receive the messages on the server side once I close the socket on the client side.
Here is the read function on the server side:
char *read_socket(int fd){
int bytesRcvd, aux;
char *buffer=(char*)malloc(BUFFSIZE*sizeof(char));
bytesRcvd=read(fd, buffer , BUFFSIZE);
aux=bytesRcvd;
while(bytesRcvd>0){
if((bytesRcvd = read(fd, &buffer[aux], BUFFSIZE))<0){
printf("read() failed!: %s\n", strerror(errno));
exit(1);
}
aux+=bytesRcvd;
}
return &buffer[0];
}
I know (by printfs) that it gets stuck on the line:
bytesRcvd = read(fd, &buffer[aux], BUFFSIZE)
Any help will be greatly appreciated.
Your program is reading the data in the line:
bytesRcvd = read(fd, &buffer[aux], BUFFSIZE)
Your while loop receives the data that the client sends. If the client doesn't have data to send read will block until the connection is closed where read will return 0 and you will exit from while loop.
This is the reason that you think that the data are send in the end (when connection is closed). This is not right, if you print the data you read in the while loop you will see them immediately and not all of them in the end.
Though you can't return the data before the connection is closed due to read() blocking.
For one client your program may seems ok if you don't have the problem of getting data at the end (as I said you could just print them inside while loop) but imagine have two or more clients then you would firstly close connection with first client to go on and read data from second and so on.
One solution(to both problems) is to use select() system call, this will go on to read only if there are data.( Though select() is not safe when using fork()- doesn't guarantee that a parent of child process will not block in read() ).
I am sending a file through TCP, and have the server sending a message containing "END_OF_MESSAGE" to alert the client that they have received the whole file and can close the socket. The file is being sent, and the client receives the "END_OF_MESSAGE" string, however, when I use strcmp to compare the received information to "END_OF_MESSAGE", it never says that they match. I have tried strncmp and memcmp but am confused as to why strcmp does not tell me the strings match.
Code snippets:
Server:
char endMessage[MESSAGESIZE] = "END_OF_MESSAGE";
if ((send(clntSocket, endMessage, sizeof endMessage, 0))!= sizeof endMessage) DieWithError("Sending failed");
The above code snippet does get sent.
Client:
if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) <= 0)
DieWithError("recv() failed or connection closed prematurely");
totalBytesRcvd += bytesRcvd; /* Keep tally of total bytes */
echoBuffer[bytesRcvd] = '\0'; /* Terminate the string! */
if (!(strcmp(echoBuffer, "END_OF_MESSAGE")==0)){
printf(echoBuffer); /* Print the echo buffer */
printf("\n");
}else{
break; //break out of while loop
}
the strcmp of the echoBuffer and "END_OF_MESSAGE" never returns 0, even though "END_OF_MESSAGE" is what I am sending from the server..I have tried strncmp to compare the first 3 characters ("END") to no avail.
Note: when I print out the echoBuffer, the very last one does print out END_OF_MESSAGE which is just adding to my confusion.
Does anyone have any insights into what I am doing wrong?
Thank you.
am sending a file through TCP, and have the server sending a message containing "END_OF_MESSAGE" to alert the client that they have received the whole file and can close the socket.
Why? Just close the socket. That will tell the client exactly the same thing..
What you're attempting is fraught with difficulty. What happens if the file contains END_OF_MESSAGE? You're going to need an escape convention, and an escape for the escape, and inspect all the data when both sending and receiving.
The actual problem that you're seeing is that END_OF_MESSAGE can arrive along with the last bit of the file, so it isn't at the start of the buffer.
But it's all pointless. Just close the socket.
I am working on an program for school and having some issues with sockets. I have pasted the write and read commands from my program below since I think these are the problem. The program should take the plaintext file and encrypt it using the key provided.
MY PROBLEM: When I execute the program using "client [plaintext] [key] [port]" the program returns "Reading data from client -- 140 bytes" and then just hangs. I can hit ctrl-c and the program prints the correct output for ptext and ktext and that 37 bytes were sent back to the client (which is the correct number of bytes). I feel like the encrypted text should print as well but it does not.
TWO QUESTIONS:
1) Why does the program hang?
2) Why does it seem like data is written from the server to the client but the client does not read any of the data?
Thank you in advance for any help you can offer.
CLIENT
n = write(sockfd,ptext,strlen(ptext));
bzero(crypt_text, BUF_MAX);
bzero(buffer, BUF_MAX);
while((n = read(sockfd,buffer,BUF_MAX))>0){
printf("Reading data from Server -- %d bytes\n",n);
strcat(crypt_text, buffer);
bzero(buffer,BUF_MAX);
}
if (n < 0){
error("ERROR reading from socket");
}
printf("%s", crypt_text);
SERVER
while((n = read(newsockfd,buffer,512))>0){
printf("Reading data from client -- %d bytes\n",n);
strcat(full_text, buffer);
bzero(buffer,BUF_MAX);
}
if (n < 0){
error("ERROR reading from socket");
}
bzero (ptext,BUF_MAX);
bzero (ktext, BUF_MAX);
strcpy(ptext, strtok(full_text,"["));
strcpy(ktext, strtok(NULL, "["));
printf("ptext length ==%s %d\n\n",ptext,strlen(ptext)); //Prints the correct plain text
printf("ktext length ==%s %d\n\n",ktext,strlen(ktext)); //prints the correct key
crypt_text = encrypt(ptext, ktext);
n = write(newsockfd,crypt_text,strlen(crypt_text));
printf("WRITE TO CILENT ==== %d",n); //This returns the correct number of bytes that should be sent back to client
if (n < 0){
error("ERROR writing to socket");
}
As is, your client and server will always hang waiting for each other. This is because read() blocks by default until new data is available to fetch from the file (in this case, a socket).
Look carefully at the code:
The client writes once into the socket before entering the read loop
The server only reads from the socket (well, further down there is a write(), but it will never reach it). The first time the loop runs on the server, it will read the data that the client initially wrote into the socket.
The server processes the data it just read and concatenates it to full_text. Then it goes back to the loop condition, where it calls read() again. read() blocks because there is nothing else to read from the socket at this point.
The client enters a similar loop where it attempts to read from the socket, expecting messages from the server.
At this point, both the server and the client are blocked waiting for messages from each other, which will never happen.
Tu put it another way: you only wrote to the socket once, and somehow you expect to read it multiple times.
You have to rethink your design. Go back to the problem description, work your way through a simple protocol, dry run it on paper, and then implement it - that's how it's done in the real world :)
There are other bugs in your code. For example you write this:
strcat(full_text, buffer);
But buffer is not NUL terminated. n bytes have been read, the rest of the buffer is indeterminate. You should set a '\0' byte at offset n and only try reading BUF_MAX-1 bytes to keep a byte available for all cases and do this:
buffer[n] = '\0';
strcat(full_text, buffer);
Furthermore, you do not test if there is enough room available in full_text for the n+1 bytes strcat will copy at the end.
On another front, packets can be sliced and diced into chunked of different sizes when received by the server. Buffering is required to ensure a reliable client / server communication. To enable this buffering, you need to devise a protocol to determine when a packet has been fully received: a simple protocol is to transmit lines terminated by '\n'.
my question is can I receive a half message with the code below?
If I want to send a message like: "MESSAGE\n"
Can that happen I receive only M character if the channel is slowly?
and the code part:
fd.fd = c->socket;
fd.events = POLLIN;
bzero(received, sizeof(received));
result = poll(&fd, 1, time);
if(result > 0)
{
i = SSL_read ( (SSL *)c->sslHandle, (char*)received, INCOMING_BUFFERSIZE);
result = SSL_get_error(c->sslHandle, i);
...
}
Because I though I receive nothing until the the "\n" symbol is not received.
How can make sure I accept message only with \n at end of that.
thanks the help,
Tamas
EDIT: the version I am using is 1.0.1c
The socket is stream-based which means that you get a stream of bytes, not a message. Consequently with one recv() call you can get from 1 to all bytes of the data you've sent. You need to put the data to some intermediate buffer and analyze the buffer for some markers (\n in your case).
Am back with C sockets question.
I am trying to receive a char array from a client via TCP. I have the following recv code:
char buffer[2048];
int recvBytes = 0;
while (1) {
if ((clntSockfd = accept(servSockfd, (struct sockaddr *) &clntAddr, &clntSockAddrLen)) == -1) {
printf("Unable to accept client connection\n");
exit(1);
}
else {
printf("Client connection accepted!\n");
}
/* clear buffer */
memset(buffer, 0, sizeof(buffer));
recvBytes = recv (clntSockfd, buffer, sizeof(buffer), 0);
printf("Bytes received: %i\n", recvBytes);
printf("Char array received: %s\n", buffer);
}
I noted that upon execution, recvBytes shows zero in the first iteration. It's only after the second iteration that it picks up the incoming char array.
I would like to find out will recv block until I receive data from the incoming socket? How should I discard the unwanted chars in the buffer - i.e. drop the chars received from the first iteration.
Many thanks!
-- edit ---
Hi all, I have appended the console output from eclipse.
**... <- initialization stuff
Binding socket to port
Socket binded
Start listening on port 8081.
Client connection accepted! *while loop - first iteration
Bytes received: 0 *while loop - first iteration
Char array received: *while loop - first iteration
Client connection accepted! *while loop - second iteration
Bytes received: 22 *while loop - second iteration
Char array received: 1~Message~HowAreYou? *while loop - second iteration**
Hope the above console output illustrates my questions clearer, regarding the first and second iterations. From the above, the first iteration is not receiving any bytes but recv does not block. I thought recv was supposed to block until it receives bytes?
I believe the recv only returns 0 if the remote end closes the connection (for stream sockets such as TCP) or if a packet with no payload is received (datagram sockets such as UDP).
If the socket has been set to non-blocking mode (default is blocking), and there's no data yet, you'd get an error code, either EAGAIN or EWOULDBLOCK depending on the OS.
In any case, each time recv returns, the new data will be stored at the beginning of the buffer. It won't append to previously received data unless you calculate a pointer designed to store new data after the old.
If your socket is a blocking socket, then recv function will block till you get some data. recv function will return 0 only when the other side closes the connection on most systems.
I suggest you recheck your code and execution and let us know the exact output.
Refer here and here for more details.
If you know what to expect of the data that you receive you can drop the first set of characters. For example if you know what will the length of the packet be or the source of the message or the header information then you can validate and ignore the first set of characters.