I'm writing simple http server, firstly let's take a look at this part of code:
static void *connection_handler(void *connection) {
/* cast the connection */
Connection *c = (Connection*)connection;
HttpRequest req;
char buffer[1024];
size_t bytes_recv = recv(c->s, buffer, 1024, 0);
parse_http_request(&req, buffer, bytes_recv);
printf("Received connection!");
//printf("%s", buffer);
/* cleanup */
krystal_close_socket(c->s);
free(connection);
return NULL;
}
this is my connection handler, every connection I push it to the vector of threads and I got strange bug. When printf with received data is commented, all "Received connection" messages show off after the server loop stops (I've set to stop server after 5 connections) but.. when I'm printing received data every connection it works, buffer is printed on every connection. WTF?!
Okay, when I added "\n" and the of the printing message it starts to working, next I've try to fflush(stdout) and still work. So my question now, is printing '\n\ character doing same thing as fflush(stdout)?
Related
There are a couple of things that I'm struggling with here.
The first is how to send a string via C stream sockets when you can't guarantee that the string will be sent/received in one go because it's larger than the BUFSIZs or for some other reason. I imagine that this needs to be done with some sort of infinite loop that you break out of, but I can't figure out how to do this.
The second is I need to do this without breaking the connection. I know that in a lot of implementations infinite loops are broken by the message sender closing the connection, which results in a recv status of 0. The recipient can then use this to break out of their loop. But is there a way of completing the transfer without breaking the connection?
EDIT: As I understand from the comments, I need to do something like the following, but this produces errors:
CLIENT CODE
char message[a_large_number];
snprintf(message, a_large_number, "%s", "a_very_long_string...");
int BUFSIZ = a_small_number;
// establish socket connection
while (1) {
int sent = send(networkSocket, message, sizeof(message), 0);
if (sent == (sizeof(message))) {
break;
}
}
// do something else
//close(socket_connection)
SERVER CODE
int BUFSIZ = another_small_number;
char client_message[];
// establish socket connection
while (1) {
char buffer[BUFSIZ];
int received = recv(clientSocket, buffer, sizeof(buffer), 0);
if (received == 0) {
break;
}
strcat(client_message, buffer);
memset(buffer, 0, sizeof(buffer));
}
// do something else
// close(socket_connection)
bool done;
done = false;
while (!done) {
/* read the message */
bzero(msg, 100);
printf("[client]Type something: ");
fflush(stdout);
read(0, msg, 100);
if (strcmp(msg, "/done") == 0) {
done = true;
/* sending the message to the server */
if (write(sd, msg, 100) <= 0) {
perror("[client]Error sending the message to the server.\n");
return errno;
}
} else {
/* sending the message to the server */
if (write(sd, msg, 100) <= 0) {
perror("[client]Error sending the message to the server.\n");
return errno;
/* reading the answer given by the server*/
if (read(sd, msg, 100) < 0) {
perror("[client]read() error from server.\n");
return errno;
}
/* printing the received message */
printf("[client]The received message is: %s\n", msg);
}
}
Here's the code that i have problem with. So i want to send messages to the server until I send the message "/done", the code works, I send messages continuously but even when i type and send "/done" the process doesn't end.
I think there's a problem with the bzero function that "clears" the msg or maybe i don't understand it so good.
I also tried to wrote my own function to check if two strings are the same, but no effect also.
So how should i write the condition or "clear" the msg so i can send messages continuously and after i send "/done" the execution ends?
P.S. the msg is declared earlier in the code as char msg[100];
When you read from 0, you're reading from stdin. If that is a terminal that you are typing into (you don't say), you likely have it set up in normal (canonical) mode, so you'll read a line, which probably includes a newline (\n) character. So when you enter /done, the string you get in your msg buffer is "/done\n" which doesn't match "/done"...
read(2) is including the '\n' at the end of the string. When you use low-level read you get everything. When trying to debug strings, it can be helpful to put quotes in your print statement, like
printf("[client]The received message is: '%s'\n", msg);
as this immediately shows invisible whitespace.
TCP is not a message protocol. It does not glue bytes together into messages. If you want to use TCP to send and receive messages, you'll need to implement functions that send and receive messages.
I must strongly caution you not to fail into the trap of thinking that changing your code from happening not to work when you tried it to happening to work when you try it means that you've fixed it. Your code fails if read returns 1. You need to implement a sensible function to receive a message or your code will only be working by luck, and I can tell you from painful experience that one day your luck will run out.
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() ).
The situation: I am creating a server daemon in c that accepts numerous simultaneous connections, and the clients will be sending data to the server. I currently have each client connection being spawned into a new thread.
The problem: if a client sends numerous lines of content very quickly (eg, 10 lines of data in less than a second), the server will see the first two lines, but not the rest.
The question: How can I "queue" the data coming in from the clients (the recv command in c)? Is this something that select or poll would be needed for? Basically, I want to make sure any client can send large amounts of data very quickly without having to worry about any content being dropped. How can this be achieved?
Sample Code: (note: the below code has obviously been heavily modified, esp. by removing error checking. I tried to modify my code so as to make the problem/solution clear without getting bogged down in semantics of irrelevant parts. Please don't get caught up with any non-standard or missing elements here)
//this function handles the threads
void *ThreadedFunction(void *arg) {
// do some stuff, like: pull vars out of mystruct
int nbytes;
char buf[256];
while(1) {
if((nbytes=recv(conid, buf, sizeof buf, 0)) <= 0) {
//handle break in connection
} else {
//for this example, just print out data from client to make my point
buf[nbytes] = 0;
printf("%s\n",buf);
}
}
}
//main just sets up the connections and creates threads
int main(int argc. char *argv[])
{
// bind(), listen(), etc... blah blah blah
while(1) {
conid = accept(...); //get a connection
// ... build mystruct to pass vars to threaded function ...
pthread_t p;
pthread_create(&p,NULL,ThreadedFunction,&mystruct); //create new thread
}
}
You don't need to "queue" the data coming in from the clients.
Because TCP do that for you. Flow control of TCP even slows down clients, if the server is too slow to make space to TCP receiving buffer.
So, probably there is bug in the code of server or client. Maybe client sends '\0' in the end of each line. In that case, the following code would not print all lines:
if((nbytes=recv(conid, buf, sizeof buf, 0)) <= 0) {
//handle break in connection
} else {
//for this example, just print out data from client to make my point
buf[nbytes] = 0;
printf("%s\n",buf);
}
It is even expected that the 2nd line is the last line what you see, if client sends '\0' at the end of each line.
For example:
If client sends the following lines:
"abc\n\0"
"def\n\0"
"ghi\n\0"
TCP will usually send those by using two packets, that contains following:
"abc\n\0"
"def\n\0ghi\n\0"
Server usually needs 2 recv calls to receive the incoming data.
So your server will use 2 print calls:
printf("%s\n", "abc\n\0\0");
printf("%s\n", "def\n\0ghi\n\0\0");
And the result output is:
abc
def
I have a very big problem... I'm working with sockets in C. I send a request to the server which sends me many responses. The problem is that the client receives the first response and then the connection is closed. What can I do? I tried with setsockopt()... SO_KEEPALIVE or SO_LINGER but I haven't resolved the problem. Can you help me? Thanks a lot
To be more clear here is the code. The socket is automatically closed after a certain amount of time or after the client received the first response... I'm not sure.
char* demarre_client( client_args * c_args,char* message, /*char* SERVEUR_PORT*/int port){
int socket_client=socket(PF_INET,SOCK_STREAM,0);
memset(&(c_args->adresse_serveur),0,sizeof(c_args->adresse_serveur));
c_args->adresse_serveur.sin_family=AF_INET;
c_args->adresse_serveur.sin_addr.s_addr=inet_addr(SERVEUR_IP);
//int port=APHash(SERVEUR_PORT,strlen(SERVEUR_PORT));
c_args->adresse_serveur.sin_port=htons(port);
int err=0;
if ((err=connect(socket_client, (struct sockaddr *) &(c_args->adresse_serveur), sizeof(c_args->adresse_serveur)))<0)
{
printf("CONNECT error %d\n", errno);
exit(-1);
}
if (send(socket_client, message, strlen(message), 0)!=strlen(message))
{
printf("send error!!\n");
exit(-2);
}
char* raspFin=(char* )malloc(sizeof(char)*1024);
strcpy(raspFin,"");
int num=-1;
int nn=0;
char* rasp=(char* )malloc(sizeof(char)*1024);
memset (rasp, 0, 1024 * sizeof(char ));
/* here it reads the first response and after he get out of while */
while ((num=recv(socket_client, rasp,1024,MSG_WAITALL))>0)
{
printf("recu %s mun=%d\n" , rasp,num);
strcat(raspFin,rasp);
strcat(raspFin,"\n");
rasp=(char* )malloc(sizeof(char)*1024);
memset (rasp, 0, 1024 * sizeof(char ));
}
if (num<0)
{
printf("rasp error!!\n");
exit(-3);
}
Are you sure you don't get all responses on first call?
TCP/IP is stream protocol without flow control built-in so different messages, sent using separate send() calls, can be received in one recv(). Because you use printf(), it prints the buffer until it sees null-terminator - maybe other responses beyond the terminator?
Try to use some flow control, like sending message length prefix or using some special characters (like STX/ETX, but make sure your message doesn't contain such characters). You'd need to implement some flow-control anyway if you plan to use this software.
For now try replacing your printf() with
char *ptr;
for (ptr = buffer; ptr <= buffer + num; ptr += strlen(ptr)+1;)
printf("%s\n", ptr);
It will print all strings from your response buffer.
And you don't need malloc() inside the loop - you leak memory.
BTW SO_KEEPALIVE and SO_LINGER have nothing to do with this problem.
My suggestion would be to fire up Wireshark network analyzer and see what's happening packet-wise. In filters set
tcp.srcport == <insert_server_port> || tcp.dstport == <insert_server_port>
You should see what data actually gets sent to and who closes the connection (sends FIN/RST packets).