I am having a printing issue with my server. I want there to be simultaneous printing when I have 2 or more clients active on terminals. However, I am only printing from one client at a time. Once I close a client, the other clients are free to write to the server. What can I do to fix my problem?
I have tried to fork the printing section, which I think didn't really do anything. (Just realized if I do this, then the select system call is a waste, i'd rather use the select system call) *edit
while(TRUE) {
FD_ZERO(&readfds);
FD_SET(socket1, &readfds);
FD_SET(socket2, &readfds);
FD_SET(socket3, &readfds);
select(socket3+1, &readfds, NULL, NULL, NULL);
//add socket1
if(FD_ISSET(socket1, &readfds)) {
if((client_socket1 = accept(socket1, NULL, NULL)) < 0) {
perror("accept1");
exit(EXIT_FAILURE);
}
printf("New Connection\n");
puts("Welcome message1 sent successfully\n");
}
//add socket2
if(FD_ISSET(socket2, &readfds)) {
if((client_socket2 = accept(socket2, (struct sockaddr *)&addr2, (socklen_t*)&addr2)) < 0) {
perror("accept2");
exit(EXIT_FAILURE);
}
printf("New Connection\n");
puts("Welcome message2 sent successfully\n");
}
//add socket 3
if(FD_ISSET(socket3, &readfds)) {
if((client_socket3 = accept(socket3, (struct sockaddr *)&addr3, (socklen_t*)&addr3)) < 0) {
perror("accept3");
exit(EXIT_FAILURE);
}
printf("New Connection\n");
puts("Welcome message3 sent successfully\n");
}
//print from socket 3
while( (ready = read(client_socket3, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
//print from socket 2
while( (ready = read(client_socket2, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
//print from socket 1
while( (ready = read(client_socket1, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
}
You need to add your client sockets to the fd_set and select statement before attempting to read from them. Also, you should make all your sockets non-blocking. Otherwise, the read call will block until you get data.
Here's a quick fix that uses recv instead of read to read the sockets, but with the async flag of MSG_DONTWAIT.
I didn't see anywhere where you were closing your client sockets or handling errors properly. So I inserted some code as a hint. Also, it's never a good idea to "printf" a buffer of data from a socket directly. Because you never know if the data you received is null terminated. Always null terminate your buffer after you read the data off the socket.
Change this block of code:
//print from socket 3
while( (ready = read(client_socket3, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
To this:
while (1)
{
int result;
result = recv(client_socket3, buffer, sizeof(buffer)-1, MSG_DONTWAIT);
if ((result == -1) &&
((errno == EAGAIN) || (errno==EWOULDBLOCK)) )
{
// no more data available, but could be available later
// use the socket with "select" above to wait for more data
}
else if ((result == -1) || (result == 0))
{
// remote close or unrecoverable error
close(client_socket3);
client_socket3=-1;
}
else
{
// null terminate the buffer before printing
buffer[result] = '\0';
printf("%s\n", buffer);
}
}
Related
I want to find a way to exit from the "loop in question" (see below) with keeping the program running, I mean : In the program there must be the message: "preparing to send informations, exit to stop !" if the user doesn't type exit, the program must still running without waiting the user to click in a character and then enter. The informations must be sent continuously until the user type exit to quit the program.
I hope I explain well the problem, and I'm sure that there is an easy solution
Thank you in advance for your help
do
{
/* menu */
printf("\r\n");
printf("1 : Start, Sending Informations.\r\n");
printf("2 : Quit.\r\n");
printf("choice : ");
scanf("%d", &nChoice);
printf("\n Trying to do a connection \n \r");
/* if connection is not established, call accept, TCP SERVER */
if (fd_client == -1)
{
printf("ready to accept...\n");
fd_client = accept(fd_listen, (struct sockaddr*)&client_addr, &addrlen);
if (fd_client >= 0)
{
printf("accept: %s, port %d\r\n", inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));
}
}
if (fd_client < 0)
{
printf(" connection is not established, continue to accept\n");
/*connection is not established, continue to accept*/
continue;
}
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_ZERO(&efd);
FD_SET(fd_tty, &rfd);
FD_SET(fd_client, &rfd);
maxfd = (fd_tty > fd_client ? fd_tty : fd_client) + 1;
/*connection is established, call select to see if any data arrived from the GPS*/
printf("connection is established, seeing if any data arrived\n");
char chaine1[256];
char chaine2[] = "exit";
int i;
if (nChoice == 1)
{
do // THE LOOP IN QUESTION
{
printf("preparing to send informations, exit to stop !\n");
i = strcmp(chaine1, chaine2); // Building the condition to exit
scanf("%s", chaine1);
fflush(stdin);
// printf ("i= %d\n",i);
ret = select(maxfd, &rfd, &wfd, &efd, &tm);
if (ret < 0) // Select failed
{
printf("select fail\r\n");
break;
}
else if (ret == 0)
{
continue; /*no data arrived, continue to call select*/
}
else
printf("data is arriving \n");
if (FD_ISSET(fd_tty, &rfd)) /*tty port has data to be read*/
{
ret = read(fd_tty, buf, sizeof(buf));
if (ret <= 0)
{
printf("read tty port fail\r\n");
break;
}
if (send(fd_client, buf, ret, 0) < 0) /*send data to ethernet*/
{
printf("send to ethernet fail\r\n");
break;
}
}
if (FD_ISSET(fd_client, &rfd)) /*tcp client has data to be read*/
{
ret = recv(fd_client, buf, sizeof(buf), 0);
if (ret < 0)
{
printf("read from ethernet fail\r\n");
break;
}
else if (ret == 0)
{
printf("disconnect by remote\r\n");
close(fd_client);
fd_client = -1;
continue; /*continue to accept...*/
}
if (write(fd_tty, buf, ret) < 0) /*send data to tty port*/
{
printf("write to tty fail\r\n");
break;
}
}
} while (i != 0 ); // The exit condition
}
} while(nChoice != 2);
Simple thing you can do is to wait for a timeout. But with scanf you can't do that so you can go for a select() call for the event at stdin and proceed if no event within that time.
Please check the following link
http://cboard.cprogramming.com/c-programming/96544-unblock-scanf-call.html
Hope this helps.
i think it should be noted that fflush(); is designed for output streams and is undefined when used on input streams, 1 way to get around the problem would be scanf(" %s", chaine1); or create a function to clear input buffer.
I am trying to create a server and client program that sends a string from client to server where the server executes that string and sends the output back to the client. I am doing this in linux and I am very confused why my program isnt working the least bit. Here is the code.
**Client**
int main()
{
//Code to use unix socket here
if (connect(s, (struct sockaddr *)&remote, len) == -1) {
perror("connect");
exit(1);
}
printf("Connected.\n");
while(printf("> "), fgets(str, MAX, stdin), !feof(stdin)) {
if (send(s, str, strlen(str), 0) == -1) {
perror("send");
exit(1);
}
}
done=0;
do {
if(t=recv(s, str, MAX, 0)<0)
perror("recv failed at client side!\n");
str[t] = '\0';
if(strcmp(str, "ENDOFTRANS")==0)
{
printf("\nRead ENDOFTRANS. Breaking loop.\n");
done=1;
}
printf("Server > %s", str);
} while(!done);
}
And then the server code is:
**Server**
#define MAX 1000
int main(void)
{
//Unix socket code
//This process is now a daemon.
daemon();
//Listens for client connections, up to 5 clients can queue up at the same time.
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
for(;;) {
int done, n, status;
printf("Waiting for a connection...\n");
t = sizeof(remote);
if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done = 0;
do {
switch(fork())
{
case -1: //ERROR
perror("Could not fork.\n");
break;
case 0: //CHILD
//Accept string from client.
//Edit: Why am I getting an error here? says: Invalid argument.
if(n = recv(newsock, str, MAX, 0)) {
perror("Recv error at server side.\n");
exit(1);
}
str[n]='\0';
if (n <= 0) {
if (n < 0)
perror("recv");
done = 1;
}
printf("String=>%s<",str);
//Redirect socket to STDOUT & STDERR.
test = close(WRITE); assert(test==0);
test = dup(newsock); assert(test==WRITE);
test = close(ERROR); assert(test==0);
test = dup(newsock); assert(test==ERROR);
if (!done)
{
if (str==something)
{
//execute command
}
else {
//Fork and execvp the command
}
//Sends End of Transaction character.
ENDTHETRANS();
exit(0);
}
break;
default: //PARENT
//Parent keeps accepting further clients.
wait(&status);
if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done=1;
break;
}
} while (!done);
}
close(s);
}
Im relatively new to programming in general and from my understanding the client code is good except that when it recieves the text back from the server it only recieves the text in small bits (2 rows at a time). I have to keep pressing enter on client promt to get the rest of the input. I have tried so many things that by this point I dont even know what I am doing wrong anymore.
Firstly, in the server code, after it recieves the string from the client I have a printf("String=>%s<",str); that outputs the string. However when the server prints the output as String=>ls -l the < key at the end gets eaten up somehow. It shouldnt be doing that right?
Any help much appreciated. Please bare in mind that I am a beginner and have only used pipes as inter process communcation before. Now I wanna make my first unix socket program.
Thanks in advance.
The usual problem in cases such as this is not realizing that SOCK_STREAM sockets don't preserve message boundaries. So data sent with a send call might be split up and received in multiple recvs, or it might be coalesced and multiple sends end up in a single recv. Most importantly, when a kernel send buffer fills up, a send call might write partial data (sending only some of the requested data) and return a short return value. You need to test for this and resend the rest of the data.
Another problem that often shows up is issues with line endings (particularly when talking between linux and windows). There may be extra carriage return characters (\r) in the either the client or server that confuse the other side. These tend to result in apparently missing or truncated output when printed.
edit
The line
if(t=recv(s, str, MAX, 0)<0)
is equivalent to
if(t = (recv(s, str, MAX, 0)<0))
that is, it sets t to 0 or 1 depending on whether there was an error or not. As with most errors of this type, turning on warnings will give you some indication about it.
I have a simple server program written in C, and the program is running on an Ubuntu Linux distribution. The program is intended to listen for messages sent from the client, write those messages to a file (each message goes into a separate file), and send an acknowledgement back to the client once the message has been received and stored.
I have noticed that, as the server continues to receive and store messages, the amount of available system memory quickly decreases and continues to decrease until messages have stopped. Memory remains constant when no messages are being sent. However, I have also noticed that I can free up the memory again by deleting the written files from disk (I can do this even while the server is still running). I am therefore led to believe that the memory issue has something to do with my file operations, though I can't see any issue with the code that writes the files.
Can someone help?
NOTE: I am observing the memory usage with "top".
I have included an excerpt from the program. The below function handles input from the client and writes that information to file. This is where I currently believe the problem to be:
void handleinput (int sock)
{
char filename[strlen(tempfolder) + 27];
generatefilename(filename);
int rv;
int n = 1;
int received = 0;
char buffer[BUFFER_SIZE];
FILE *p = NULL;
fd_set set;
char response[768];
struct timeval timeout;
timeout.tv_sec = 360;
timeout.tv_usec = 0;
FD_ZERO(&set);
FD_SET(sock, &set);
bzero(buffer, BUFFER_SIZE);
bzero(response, sizeof response);
rv = select(sock + 1, &set, NULL, NULL, &timeout);
if (rv == -1)
{
error("error on select in handleinput");
close(sock);
exit(1);
}
else if (rv == 0)
{
close(sock);
exit(0);
}
else
{
n = read(sock, buffer, BUFFER_SIZE-1);
if (n <= 0)
{
close(sock);
exit(0);
}
}
// open file
if (n != 0)
{
p = fopen(filename, "a");
if (p == NULL)
{
error("ERROR writing message to file");
close(sock);
exit(1);
}
}
// loop until full message is received
while (n != 0)
{
if (n < 0)
{
error("ERROR reading from socket");
close(sock);
exit(1);
}
received = 1;
// write content to file
fwrite(buffer, strlen(buffer), 1, p);
if (buffer[strlen(buffer)-1] == 0x1c)
{
break;
}
bzero(buffer, BUFFER_SIZE);
rv = select(sock + 1, &set, NULL, NULL, &timeout);
if (rv == -1)
{
error("ERROR select in loop in handleinput");
close(sock);
exit(1);
}
else if (rv == 0)
{
close(sock);
exit(0);
}
else
{
n = read(sock, buffer, BUFFER_SIZE-1);
}
}
// close file if we opened it earlier
if (p != NULL)
{
fclose(p);
}
// send acknowledgement back to client
if (received == 1)
{
generateResponse(response, filename);
n = write(sock, response, strlen(response));
if (n < 0)
{
error("ERROR writing to socket");
close(sock);
exit(1);
}
}
}
Its because of the caching mechanism of writing. IF you have a lot of clients trying to write files, the IO buffer fills in kernel memory, but doesn't actually write to that file until you close the socket or the buffer fills. You can fix this just by flushing the buffer. What some other people have suggested is to get rid of the write and read wrappers in stdio, and just use the kernel call write, since this will help performance and will probably flush the buffer automatically.
You can flush with fsync() btw.
The objective of my program is to use select to manage multiple sockets. However, I thought of trying it with one socket first. Now, the problem that I am facing is that initially client sends data to server, and server receives it and displays it, but then when client again sends some data, the server code remains still at select command.
here are some snippets that will give you an idea of how I am initializing the socket.
if((master_socket = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
exit(1);
}
if((bind(master_socket, (struct sockaddr *)&req, sizeof(req))) < 0)
{
exit(1);
}
listen(master_socket, 5);
FD_SET(master_socket,&listening);
/* wait for connection, then receive and print text */
len = sizeof(struct sockaddr);
while(1)
{
FD_ZERO(&listening); //Flush out everything in socket
FD_SET(master_socket,&listening); // Add master
if(f_client>0) // Add client if any
{
FD_SET(f_client,&listening);
}
printf("Checking for new connection \n");
//Timeout is null, so waiting indefinitely
rc = select(FD_SETSIZE, &listening, NULL, NULL, NULL);
if (FD_ISSET(master_socket, &listening))
{
printf("Master side invoked\n");
if((f_client = accept(master_socket, (struct sockaddr *)&req, &len)) < 0)
{
exit(1);
}
}
else if (FD_ISSET(f_client,&listening))
{
if ((valread = read( f_client , buf, 1024)) == 0)
{
close(f_client);
f_client=0;
}
else
{
fputs(buf, stdout);
}
}
}
Basically in above program, it connects to the server, maintains a file descriptor for client f_client and add it. And in every round, it clears the socket, add master socket, and client socket if any, and then checks. Problem here is, first time it works, but second time when client sends some data. it gets hang to rc = select(FD_SETSIZE, &listening, NULL, NULL, NULL);
I am not to understand what is wrong here. Can anyone help?
if ((valread = read( f_client , buf, 1024)) == 0)
{
close(f_client);
f_client=0;
}
else
{
fputs(buf, stdout);
}
This code is broken. The fputs function can only be used with a C-style string. You just have arbitrary data with no particular structure. Since you ignore valread, you also have no idea how many bytes you read. (Think about it, how could fputs possibly know how many bytes to output? That information is only in valread, and you don't pass it that information.)
You've already received the data, this broken code just threw it away. If you log valread, you'll see that you actually already read it in your last call to read before the call to select that hung.
instead of fputs, you could use something like this:
for (int i = 0; i < valread; ++i)
putchar(buf[i]);
I was just going through the Networking Guide by Beej and am curious about this part of the code (specifically marked with "From here" and "To here"):
// main loop
for(;;) {
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
// run through the existing connections looking for data to read
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { // we got one!!
if (i == listener) {
// handle new connections
addrlen = sizeof remoteaddr;
newfd = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);
if (newfd == -1) {
perror("accept");
} else {
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) { // keep track of the max
fdmax = newfd;
}
printf("selectserver: new connection from %s on "
"socket %d\n",
inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN),
newfd);
}
} else {
// handle data from a client
//----------------- FROM HERE --------------------------
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
// connection closed
printf("selectserver: socket %d hung up\n", i);
} else {
perror("recv");
}
close(i); // bye!
FD_CLR(i, &master); // remove from master set
//----------------- TO HERE ----------------------------
} else {
// we got some data from a client
for(j = 0; j <= fdmax; j++) {
// send to everyone!
if (FD_ISSET(j, &master)) {
// except the listener and ourselves
if (j != listener && j != i) {
if (send(j, buf, nbytes, 0) == -1) {
perror("send");
}
}
}
}
}
} // END handle data from client
} // END got new incoming connection
} // END looping through file descriptors
} // END for(;;)--and you thought it would never end!
return 0;
Now I know that read doesn't always read "everything" that is to be read on a socket and that it sometimes can return only part of it. In that case, wouldn't this code be incorrect? I mean, after one read, the connection is being closed... Instead, aren't we supposed to have some other mechanism in place? If so, what is the right approach here?
The socket is only going to get closed there if there was an error from recv(), otherwise it'll deal with the data that was read even if it isnt all read. It will then read more out when it loops through again. Pretty sure this is what you're asking?
Yes you would keep reading until you got all the data you expected, obviosuly you need someway of knowing how much to expect - which is why http puts the document size first
Your only calling close when recv() has returned a negative value which means that recv had some sort of error. Notice that the block where you do the close has a comment stating // got error or connection closed by client).
When you actually get some data (the else branch starting with // we got some data from a client), the connection is not being closed.
You are right that you can't assume the data arrives all at one time. Your mistake is in following how the code is working.