I'm trying to implement a simple multi-threaded client/server program: the client sends the server a number and the server creates a thread that sends back the number+1.
The problem is as follows:
The client connects to the server with no problems;
The thread is (as far as i can tell) created without issues; But after the client writes the number in the socket, the server simply doesn't see it. The call to read() gives no errors, it just sits there, waiting forever.
I tried sending more than one integer through it; no difference.
A suspicion i have is that the file descriptor server-side is passed incorectly to the thread,but i can't figure out how. Another suspicion i have is that i am missing something stupidly obvious.
Either way, help is appreciated.
Any ideas?
Server-side: the loop that creates threads.
while (1) {
int client;
printf("[server]Waiting at port %d...\n", PORT);
fflush(stdout);
int length = sizeof(from);
if (client = accept(sd, (struct sockaddr*)&from, &length) < 0) {
perror("[server]Error: accept().");
continue;
}
pthread_t th_id;
pthread_create(&th_id, NULL, &treat, &client);
}
Server-side: thread's treat function (the problem is here).
void* treat(void* client)
{
printf("[thread]Waiting for message...\n");
fflush(stdout);
pthread_detach(pthread_self());
int client_sd = *((int*)client);
int nr;
if (read(client_sd, &nr, sizeof(int))) {
perror("[thread]Error: read().");
exit(-1);
}
// The program won't reach this point.
printf("[thread]Read: %d", nr);
fflush(stdout);
close(*((int*)client));
return (NULL);
}
Client-side:
if (connect (sd, (struct sockaddr *) &server,sizeof (struct sockaddr)) == -1)
{
perror ("[client]Error: connect().\n");
return errno;
}
printf ("[client]Write a number: ");
fflush (stdout);
scanf("%d",&nr);
printf("[client] Read %d\n",nr);
if (write (sd,&nr,sizeof(int)) <= 0)
{
perror ("[client]Error: write()\n");
return errno;
}
//the program reaches here.
printf("[client]The message was sent\n");
The problem is at line
if (client = accept(sd, (struct sockaddr*)&from, &length) < 0) {
it is interpreted as
if (client = (accept(sd, (struct sockaddr*)&from, &length) < 0)) {
and if accept returns positive then the client is set to 0. Subsequent read in the thread is read from stdin then.
Related
I am writing a program which is supposed to act as a simple proxy between a web server and a browser. The browser connects to my proxy program and my program connects to the web server. My proxy program should simply forward all data it receives from the browser to the web server and vice-versa, without modifying the data in any way and without performing any caching.
I have managed to get a reply from a web server but how would I direct that reply to my browser? Also is there any way to put this into some sort of infinite loop where I can recv and send at will?
Edit:
I've almost got it. I just need to know how to continuously read the sockets. The program closes unexpectedly after I get the Http redirect.
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#define SERVER_PORT 8080
#define SA struct sockaddr
#define MAX 80
pthread_t ptid, ptidd;
#define TRUE 1
#define FALSE 0
struct sockets_struct {
int server_sd;
int client_sd;
int new_sd;
}socks;
// Function designed to act as client.
void *client_func(void *sockets)
{
char buffer[MAX];
struct sockaddr_in servaddrr;
struct sockets_struct *socks = (struct sockets_struct*)sockets;
int i, len, rc, on = 1;
//bzero(&servaddrr, sizeof(servaddrr));
// assign IP, PORT
servaddrr.sin_family = AF_INET;
servaddrr.sin_addr.s_addr = inet_addr("192.168.0.1");
servaddrr.sin_port = htons(80);
// connect the client socket to server socket
if (connect(socks->client_sd, (SA*)&servaddrr, sizeof(servaddrr)) != 0) {
printf(" client: connection with the server failed...\n");
exit(0);
}
else
printf(" client: connected to the remote server..\n");
do {
rc = recv(socks->client_sd, buffer, sizeof(buffer), 0);
if (rc < 0) {
if (errno != EWOULDBLOCK) {
perror(" client: recv() failed\n");
}
break;
}
if (rc == 0) {
printf(" client: Connection closed\n");
break;
}
len = rc;
printf(" client: %d bytes received\n", len);
rc = send(socks->new_sd, buffer, len, 0);
if (rc < 0) {
perror(" client: send() failed");
break;
}
} while(TRUE);
}
// Function designed to act as server.
void *server_func(void *sockets)
{
int len, rc, on = 1;
int desc_ready, end_server = FALSE, compress_array = FALSE;
int close_conn;
char buffer[80];
struct sockaddr_in6 addr;
int timeout;
struct pollfd fds[200];
int nfds = 1, current_size = 0, i, j;
struct sockets_struct *socks = (struct sockets_struct*)sockets;
rc = setsockopt(socks->server_sd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (rc < 0) {
perror(" server: setsockopt() failed\n");
close(socks->server_sd);
exit(-1);
}
rc = ioctl(socks->server_sd, FIONBIO, (char *)&on);
if (rc < 0) {
perror(" server: ioctl() failed\n");
close(socks->server_sd);
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET;
memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
addr.sin6_port = htons(SERVER_PORT);
rc = bind(socks->server_sd, (struct sockaddr *)&addr, sizeof(addr));
if (rc < 0) {
perror(" server: bind() failed");
close(socks->server_sd);
exit(-1);
}
rc = listen(socks->server_sd, 32);
if (rc < 0) {
perror(" server: listen() failed");
close(socks->server_sd);
exit(-1);
}
memset(fds, 0 , sizeof(fds));
fds[0].fd = socks->server_sd;
fds[0].events = POLLIN;
timeout = (3 * 60 * 1000);
do {
printf(" server: waiting on poll()...\n");
rc = poll(fds, nfds, timeout);
if (rc < 0) {
perror(" server: poll() failed\n");
break;
}
if (rc == 0) {
printf(" server: poll() timed out. End program.\n");
break;
}
current_size = nfds;
for (i = 0; i < current_size; i++) {
if (fds[i].revents == 0)
continue;
if (fds[i].revents != POLLIN) {
printf(" server: Error! revents = %d\n", fds[i].revents);
end_server = TRUE;
break;
}
if (fds[i].fd == socks->server_sd) {
printf(" server: Listening socket is readable\n");
socks->new_sd = accept(socks->server_sd, NULL, NULL);
if (socks->new_sd < 0) {
if (errno != EWOULDBLOCK) {
perror(" server: accept() failed\n");
end_server = TRUE;
}
break;
}
printf(" server: new incoming connection - %d\n", socks->new_sd);
fds[nfds].fd = socks->new_sd;
fds[nfds].events = POLLIN;
nfds++;
}
else {
printf(" server: Descriptor %d is readable\n", fds[i].fd);
close_conn = FALSE;
do {
rc = recv(fds[i].fd, buffer, sizeof(buffer), 0);
if (rc < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
close_conn = TRUE;
}
break;
}
if (rc == 0) {
printf(" server: Connection closed\n");
close_conn = TRUE;
break;
}
len = rc;
printf(" server: %d bytes received \n", len);
rc = send(socks->client_sd, buffer, len, 0);
if (rc < 0) {
perror(" server: send() failed\n");
close_conn = TRUE;
break;
}
} while(TRUE);
if (close_conn) {
close(fds[i].fd);
fds[i].fd = -1;
compress_array = TRUE;
}
} /* End of existing connection is readable */
} /* End of loop through pollable descriptors */
} while (end_server == FALSE); /* End of serving running. */
}
int main (int argc, char *argv[])
{
socks.server_sd = socket(AF_INET, SOCK_STREAM, 0);
socks.client_sd = socket(AF_INET, SOCK_STREAM, 0);
if (socks.server_sd == -1) {
printf("socket \"server_sd\" creation failed...\n");
exit(0);
}
else
printf("Socket \"server_sd\" successfully created..\n");
if (socks.client_sd == -1) {
printf("socket \"client_sd\" creation failed...\n");
exit(0);
}
else
printf("Socket \"client_sd\" successfully created..\n");
pthread_create(&ptidd, NULL, &client_func, &socks);
pthread_create(&ptid, NULL, &server_func, &socks);
pthread_join(ptidd, NULL);
return 0;
}
You can either write a proxy that understands the data it's proxying or one that doesn't. Your question suggests that you want to write one that doesn't. That is definitely the easier approach.
So once all the connections are setup, you have two things to do. You need to read data from one connection and send it to the other. You also need to read data from the other connection and send it to the first one.
Using two threads is an easy way to do this. You can also fork a process for each direction. But the first way that everyone learns is a select or poll loop. You can punch "select loop proxy" into your favorite search engine to find lots of examples.
NOTE: This answer was written at a time before the OP edited the question and added threads to the code in the question.
The main problem I see with your algorithm is that you seem to assume that you will always receive all data from the client and server in one recv or read call. This cannot be relied upon, even if the web client (browser) only sends a single HTTP request (which is very unlikely, even if only one web page gets loaded).
I suggest you use the following algorithm instead:
Wait for web client (browser) to establish connection to your program.
Create a new socket which connects to web server.
Wait for web server connection to be established. This step is not necessary with your program, as you are using a blocking connect call. It is only necessary if non-blocking or asynchronous sockets are used.
Wait for new data to be available to be read on either of the two sockets, for example by using the function select. When this function returns, it will indicate on which sockets a non-blocking call to recv is possible.
Read from the socket(s) that select reports as having data available to be read, and write this data to the other socket using the send function.
Go to step 4.
However, this algorithm has one possible problem: It assumes that send will always be successful at writing all the bytes immediately, without blocking. Depending on the circumstances (for example the operating system's buffering of sockets) this may not always be the case. It may only be able to partially send the contents of the buffer at once. The documentation of the function send does not specify what will happen if the buffer of the send function is too large to be sent at once, i.e. whether it will block until all the data is sent or whether it will return as soon as it was able to perform a partial send.
Therefore, your algorithm should be able to deal with the case that the data is only partially sent, for example by also checking in step 4 whether it is possible to write more data if not all data was written in a previous call to send.
Also, beware that while your program is blocking on a send call, it will not process any communication in the other direction. For example, while your program is blocking on a send call while forwarding data from the client to the server, it will be unable to forward any data from the server to the client. I don't think that this can cause trouble with the HTTP protocol, because the client and server never send data simultaneously, as the server always waits for the client to finish its request and the client then waits for the server to finish its reply, before it sends another request. However, this may be an issue with other protocols. In particular, if you block communication completely in one direction, this may cause the client or server to get stuck on a blocking send or recv call, too. This could cause a deadlock in all three programs.
Therefore, you may want to consider using non-blocking sockets or asynchronous sockets instead, so that you can continue forwarding network traffic in both directions at all times.
Alternatively, you could continue using blocking socket calls and create two threads, one for forwarding data from the client to the server and one for forwarding data from the server to the client. That way, communication will never be blocked in any direction. But I would recommend using non-blocking sockets or asynchronous socket instead, as threads can get messy.
One thing your algorithm should also do is handle an orderly socket shutdown (indicated by recv returning 0) and error conditions. How to do this depends on what kind of sockets you are using, i.e. whether they are blocking, non-blocking or asynchronous.
I'm trying to write a program which either reads from a socket or from stdin. If socket then print to stdout (to user), otherwise print to socket. So far I'm using poll to awake program when there's activity on either, my problem is that after the initial connection, poll always reports activity on the socket, even though client hasn't written anything else.
Is there any way to distinguish between "someone has connected to the socket" and "someone put a message on the channel"? Looking through man pages for poll, select and others I don't really see an appropriate flag.
If there is no appropriate flag, what would be a way to accomplish what I'm trying to do ?
What I currently have is something like below. When I enter something in stdin, poll returns and the loop determines the activity was on the socket (wrong).
edit: There's other issues at well but this is what I'm struggling with right now.
/* blocking accept for first and only connection */
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
/* poll stdin and newsockfd */
struct pollfd fds[2];
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
fds[1].fd = newsockfd;
fds[1].events = POLLIN;
ioctl(newsockfd, FIONBIO, (char *)&on); /* int on = 1 */
while (1) {
int rc = poll(fds, 2, -1);
if (rc <= 0)
exit(1);
for (int i = 0; i < 2; i++) {
if (fds[i].revents == 0)
continue;
if (fds[i].revents != POLLIN)
exit(1);
if (fds[i].fd = newsockfd) {
n = read(newsockfd, buffer, 255);
printf("read %d chars from newsockfd: %s\n", n, buffer);
} else if (fds[i].fd = STDIN_FILENO) {
read(STDIN_FILENO, buffer, 255);
n = dprintf(newsockfd, "%s", buffer);
printf("wrote %d chars to newsockfd: %s\n", n, buffer);
}
}
}
The program creates n threads for simulating n nodes in a distributed system, each has one socket it listens to and each thread can communicate to n-1 other threads through connect calls.
Each thread makes a call to select() to see if anything's available and if so accepts and saves the data.
I use ioctl with the flag FIONREAD to check the number of bytes available to be read and do an appropriate read call. Afterwards the new fd (from accept()) is closed.
The listening sockets are blocking. O_NONBLOCK is NOT set.
All n threads run the same function. All variables declared within the function use thread local storage.
There's no explicit synchronization done on my part. More than one thread can try to connect to the same socket at once.
Now, the problem is, once in a while, the select() in a thread on the receiving side notes something new but the amount of bytes available is 0 which it shouldn't be. This happens inconsistently.
Would be great if someone can point where I should look into. Thanks!
creating the sock
if ( (nptr->sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
fd_max = nptr->sock > fd_max ? nptr->sock : fd_max;
int ok=1;
setsockopt(nptr->sock, SOL_SOCKET, SO_REUSEADDR, &ok, sizeof(int));
nptr->addr.sun_family = AF_UNIX;
snprintf(nptr->addr.sun_path, 20, "%d", nptr->id);
//strncpy(nptr->addr.sun_path, sock_path, 20);
if ( bind(nptr->sock, (struct sockaddr*)&(nptr->addr), sizeof(struct sockaddr_un)) < 0 ) {
perror("bind");
exit(1);
}
/* socket, max connections */
if ( listen(nptr->sock, 2*tot_node) < 0 ) {
perror("listen");
exit(1);
}
sending stuff
for (t=0; t<tot_node; t++) {
...
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
printf("Node %d: trying to req node %d... ", self->id, node_catalog[t]->id);
if ( connect(fd, (struct sockaddr*)&(node_catalog[t]->addr), sizeof(struct sockaddr_un)) == -1 ) {
perror("connect");
exit(1);
}
buf[0] = TYPE_REQ;
buf[1] = self->id;
buf[2] = ts;
buf[3] = rsc;
write (fd, buf, 4*sizeof(int));
//close(fd);
printf("Node %d: sent req for resource %d to %d\n", self->id, rsc, node_catalog[t]->id);
}
usleep(TS_UPDATE_ITV);
receiving stuff
FD_ZERO(&readset);
FD_SET(self->sock, &readset);
t = pselect(self->sock+1, &readset, NULL, NULL, &tout, NULL);
if (t > 0 && FD_ISSET(self->sock, &readset)) {
com_fd = accept(self->sock, NULL, NULL);
ioctl(com_fd, FIONREAD, &t);
#ifdef DEBUG
printf(" Node %d: received %d bytes of data\n", self->id, t);
#endif
read(com_fd, buf, t);
close(com_fd);
dptr = (int *)buf;
rsc = t / (sizeof(int)); /* var reuse. this is the count of ints to read */
for (t=0; t<rsc; ) {
static __thread int nid, nts, nrsc;
#ifdef DEBUG
printf(" Node %d: data rcvd: %d %d %d %d", self->id, *dptr, *(dptr+1), *(dptr+2), *(dptr+3));
#endif
if (*dptr == TYPE_REQ) {
... } else {...}
Your code doesn't make sense. The reason that select() fired was that there was something to accept. Checking FIONREAD on a socket you've just accepted may or may not result in data being available. It depends entirely on whether the client has sent any. Not on the contract of select().
If you need to know whether there is something to read, you should add the accepted socket to the read-FD set, and process it in a loop: if the listening socket is readable, call accept() on it, otherwise it is an accepted socket and you should call read() on it.
Checking FIONREAD is really just a waste of time in most circumstances.
I am trying to make an asynchronous UDP chat application, currently having only one client and server.
When I run my server, a lot of redundant data is displayed. Afterward, when some text is typed,
Error sending the file!
is displayed.
Could someone please look at the code and let me know where I am going wrong?
Server:
u_long iMode=1;
ioctlsocket(sd,FIONBIO,&iMode);
int n=sd+1;
fd_set readfds,writefds;
while(1)
{
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_SET(sd,&readfds);
FD_SET(sd,&writefds);
int rv = select(n, &readfds, &writefds, NULL, NULL);
if(rv==-1)
{
printf("Error in Select!!!\n");
exit(0);
}
if(rv==0)
{
printf("Timeout occurred\n");
}
if (FD_ISSET(sd, &readfds))
{
FD_CLR(sd,&readfds);
int client_length = (int)sizeof(struct sockaddr_in);
memset(&buffer,0,sizeof(buffer));
int bytes_received = recvfrom(sd, buffer,SIZE, 0, (struct sockaddr *)&client, &client_length);
if (bytes_received < 0)
{
fprintf(stderr, "Could not receive datagram.\n");
closesocket(sd);
WSACleanup();
exit(0);
}
}
printf("\nClient says: %s",buffer);
printf("\nWrite :");
fgets(buffer,SIZE,stdin);
if(FD_ISSET(sd,&writefds))
{
FD_CLR(sd,&writefds);
int client_length = (int)sizeof(struct sockaddr_in);
if(sendto(sd, buffer,strlen(buffer), 0, (struct sockaddr *) &client,client_length)<0)
{
printf("Error sending the file! \n");
exit(1);
}
}
}
closesocket(sd);
WSACleanup();
return 0;
}
I see a problem. This line:
int rv = select(n, &readfds, &writefds, NULL, NULL);
Will nearly always return immediately with the readfds empty. But writefds will almost ALWAYS be set with the "sd" socket indicating that it is ready for writing/sending.
Hence, your code correctly skips the attempt to call recvfrom(), but nothing stops it from falling through to the sending code path. All of the variables such client, client_length, and buffer as are likely uninitialized at that point. Or worse, buffer and client are exactly what they were from the last successful call in the loop. That likely explains the redundant data.
My advice would be to not have a "writefds" set in the select call at all. Then only "send" when you actually read. The sendto call won't block for any significant amount of time anyway.
This is a bit of an odd one. My code wasn't outputting what I thought it should. I added some print statements at various stages to see where it was going wrong. Still nothing.
So I added a printf statement at the start of main. That's where I got really confused.
So I presumed something funny was happening with the file descriptors. I changed the printf to a fprintf. Still nothing. Printing to stderr with fprintf does work! Why is this happening?
Removing all of the body from main except the initial print statement and the return does print.
Code
int main(void) {
fprintf(stdout, "STARTED!");
//Create an Internet domain socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
//If this fails exit and print the error
if (sockfd == -1) {
printf("Error %d, cannot create socket", errno);
return 1;
}
printf("SOCKET CREATED!");
//Creates a socket address
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
addr.sin_addr.s_addr = INADDR_ANY;
//Attempts to bind to the socket address, again prints to error if this fails.
if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
{
printf("Error %d, cannot bind", errno);
return 1;
}
//Starts Listening for a client
if (listen(sockfd, 1) == -1)
{
printf("Error %d, cannot listen", errno);
return 1;
}
//If all is successful, server is operational
while(1)
{
//Creates a file descripter for the connection
int connfd;
//And a socket address for the client
struct sockaddr_in cliaddr;
socklen_t cliaddrlen = sizeof(cliaddr);
//If a connection attempt is made accepts it.
connfd = accept(sockfd, (struct sockaddr *) &cliaddr, &cliaddrlen);
if (connfd == -1) {
//If the connection fails print an error
printf("Error %d, cannot accept connection", errno);
continue;
}
//Otherwise process the request
else {
printf("CONNECTED!");
char end;
end = 1;
while (end)
{
process_request(connfd);
end = 0;
}
}
close(connfd);
}
close(sockfd);
return 0;
}
Output is often buffered by the system. You can call fflush, but sometimes, depending on how the caching works, simply ending the output with a newline is sufficient. So try changing
fprintf(stdout, "STARTED!");
to
fprintf(stdout, "STARTED!\n");
And, if that doesn't help, to
fprintf(stdout, "STARTED!\n");
fflush(stdout)
(And stderr often isn't cached, as you want to see errors immediately.)
Finally, you will see output when the program finishes (as things are flushed then), which probably explains the rest of the behaviour.