C Board  

Go Back   C Board > General Programming Boards > Networking/Device Communication

Reply
 
LinkBack Thread Tools Display Modes
Old 11-12-2008, 12:27 AM   #1
Registered User
 
Join Date: Apr 2008
Posts: 167
Chat Program Help?

I have two files: client.c and a server.c. You can type a line on the client, press enter, and it will be displayed on the server. Then type a line on the server, press enter, and it gets displayed on the client side.

The problem is when you type two messages on either side. Then it gets buffered in memory, but won't display until after you type something on the other side. Like this:

Quote:
Client: type "Hello"
Client: type "Hello2"

Server shows: "Hello"

<Hello2 does not show>

Server: type "Hi there"

Server shows: "Hello2" (shows only after typing Hi there and pressing enter)

(The problem is exacerbated if one side types 3 or more lines. It all gets buffered and won't display until the other side types.)
Does anyone know how I could get around this problem? More of a conceptual problem I suppose.

-----

Here is my source code and a makefile (I put red/bold around the relevant while loops, the only areas I'm coding in):

Code:
CC = /usr/bin/g++
CFLAGS = -Wall -pthread -lpthread
LIBS = -lm

APP = client server
OBJS =

all: $(APP)
$(APP): $(OBJS)
	$(CC) $(CFLAGS) -g -o $@ $(OBJS) $(LIBS)

client: client.c
	$(CC) $(CFLAGS) -g -o client client.c

server: server.c
	$(CC) $(CFLAGS) -g -o server server.c

clean:
	rm -f *.o *~* $(APP)
./server 3200 // (random port #)
./client 127.0.0.1 3200 // (localhost ip and random port#)

Code:
// Client Program
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h> /*for sockaddr_in and inet_addr()*/ // V
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>

#define BUFFSIZE 256
#define SERVER_PORT 6401

int main(int argc, char** argv)
{
	int sock;
	struct sockaddr_in echoserver;
	char buffer[BUFFSIZE]={0};
	unsigned int echolen;

	int command = 0;
	char input[100];

	int received = 0;

	if(argc < 3)
	{
		printf("Usage : cli <serverip> <String> \n");
		exit(1);
	}

	if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
	{
		perror("Failed to create socket \n");
		exit(0);
	}

	memset(&echoserver, 0, sizeof(echoserver));
	echoserver.sin_family = AF_INET;
	echoserver.sin_addr.s_addr = inet_addr(argv[1]);
	echoserver.sin_port = htons(SERVER_PORT);
	if(connect(sock, (struct sockaddr *) &echoserver, sizeof(echoserver)) < 0)
	{
		perror("Failed to connect with the server \n");
		exit(0);
	}

	memcpy(buffer,argv[2],sizeof(buffer)-1);
	echolen = strlen(buffer);

	while (command != 3 && command != 4)
	{
		printf("Enter option (1 - 4): ");
		fgets(input, 100, stdin);
		command = atoi(input);

		if (command == 1)
		{
			while(input[0] != 'E' || input[1] != 'X' || input[2] != 'I' || input[3] != 'T')
			{
				fgets(input, 100, stdin);
				if (send(sock, input, sizeof(input), 0) == -1)
					perror("send error");

				if(( received = recv(sock,buffer,BUFFSIZE-1, 0)) < 0 )
				{
					perror("Failed to receive additional bytes from client \n");
				}
				if(received >0)
				{
					printf("Received from Server : %s",buffer);
				}
			}
		}
		else if (command == 2)
		{
			printf("Do 2\n");
			// Client sends url to server in format http://<server name>/
			// Server downloads index.html and sends to client's local directory
			// File saved as index.html (over-write if necessary)
		}
		else if (command == 3)
		{
			printf("Thank You.\n");
			// Disconnect Client
		}
		else if (command == 4)
		{
			printf("Thank You Very Much.\n");
			// Disconnect Client and Server
		}
		else
		{
			printf("Improper input.\n");
		}
	}

	close(sock);
}
Code:
// Server Program
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

#define BUFFSIZE 256
#define MAX_PENDING 10
#define MAX_CLIENTS MAX_PENDING

pthread_t clients[MAX_CLIENTS];
#define SERVER_PORT 6401

void *ClientData(void* arg)
{
	int sock = *(int*)arg;
	char buffer[BUFFSIZE] = {0};
	int received = -1;

	fd_set fds;
	int maxfd;
	int nready;

	char input[100];

	maxfd = sock + 1;

	while(1)
	{
		FD_ZERO(&fds);
		FD_SET(sock,&fds);

		nready = select(maxfd,&fds,0,0,0);
		if(FD_ISSET(sock,&fds))
		{
			if(( received = recv(sock,buffer,BUFFSIZE-1, 0)) <0 )
			{
				perror("Failed to receive additional bytes from client \n");
			}
			if(received >0)
			{
				printf("Received from Client : %s",buffer);
			}
			if(received < 1)
			{
				printf("Closing this client\n");
				close(sock);
				pthread_exit(NULL);
			}
			memset(buffer,0,sizeof(buffer)); // V, 0
		}
		fgets(input, 100, stdin);
		if (send(sock, input, sizeof(input), 0) == -1)
			perror("send error");
	}
	close(sock);
}

int main()
{
	int threadCount =0;

	int sock,clientsock;
	struct sockaddr_in echoserver,echoclient;
	char buffer[BUFFSIZE] = {0};

	if(( sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0 )
	{
		perror("Failed to created socket \n");
	}

	memset(&echoserver, 0, sizeof(echoserver));
	echoserver.sin_family = AF_INET;
	echoserver.sin_addr.s_addr = htonl(INADDR_ANY);
	echoserver.sin_port = htons(SERVER_PORT);

	if(bind(sock,(struct sockaddr *) &echoserver, sizeof(echoserver)) < 0)
	{
		perror("Failed to bind the socket \n");
	}
	if(listen(sock, MAX_PENDING) < 0)
	{
		perror("Failed to listen on server socket \n");
	}

	while(1)
	{
		unsigned int clientlen = sizeof(echoclient);

		if(( clientsock = accept(sock, (struct sockaddr*) &echoclient, &clientlen)) < 0)
		{
			perror("Failed to accept client connection \n");
		}
		fprintf(stdout,"Client Connected : %s \n",inet_ntoa(echoclient.sin_addr));

		if(clientsock > -1)
		{
			if(threadCount<MAX_CLIENTS)
				pthread_create(&clients[threadCount++],NULL,ClientData,(void *) &clientsock);
		}
	}
}
Paul22000 is offline   Reply With Quote
Old 11-12-2008, 12:37 AM   #2
mastering the obvious
 
MK27's Avatar
 
Join Date: Jul 2008
Location: SE Queens
Posts: 5,071
Using fgets at the end of the while (1) loop in the server will guarantee that the loop is paused and waiting for local input before it checks the socket again. These two processes cannot really be in the same loop.
__________________

“The essential element in the black art of obscurantism is not that it wants to darken individual understanding, but that it wants to blacken our picture of the world, and darken our idea of existence.” [Friedrich Wilhelm Nietzsche, 1878]

Last edited by MK27; 11-12-2008 at 12:45 AM.
MK27 is online now   Reply With Quote
Old 11-12-2008, 12:40 AM   #3
Registered User
 
Join Date: Apr 2008
Posts: 167
Quote:
Originally Posted by MK27 View Post
Using fgets at the end of the while (1) loop in the server will guarantee that the loop is paused and waiting for local input before it checks the socket again.
Is there another function I can use?

I thought about using scanf but that will yield the same problem.
Paul22000 is offline   Reply With Quote
Old 11-12-2008, 01:32 AM   #4
mastering the obvious
 
MK27's Avatar
 
Join Date: Jul 2008
Location: SE Queens
Posts: 5,071
The problem is not that you use fgets. The problem is that you use fgets at the end of the while loop. select can be made to check for input from a file descriptor and, if there is none, move on. But fgets cannot. If you call fgets, it is going to wait for input.

I'm no pro, I don't use windows, and I just started with c in the summer, but I have written an ncurses forking (local socket) server and client which works well (you can send messages back and forth without this problem, etc). Unfortunately, I haven't gotten into pthreads yet, so I'm not sure of the syntax, but logically YOU MUST seperate the process which waits for input from the socket from the process which waits for input locally. With fork, this means you have the child in the server monitoring connected sockets via select, while the parent waits for keyboard input and sends it. With pthreads, I suspect you must use seperate function calls. Hopefully someone out there can fill in the gaps for us.

The key point: once you call fgets, or scanf, or whatever you want to use for local input, that command is going to wait until there is local input, and nothing else will happen. You have to use seperate, parallel loops.

If you don't have much experience with pthreads you should use fork until you get this working. I found the use of sockets for inter-process communication very tricky, relatively speaking, and I suspect you still have a long way to go but you are getting there.
__________________

“The essential element in the black art of obscurantism is not that it wants to darken individual understanding, but that it wants to blacken our picture of the world, and darken our idea of existence.” [Friedrich Wilhelm Nietzsche, 1878]
MK27 is online now   Reply With Quote
Old 11-12-2008, 02:57 AM   #5
Registered User
 
Join Date: Apr 2008
Posts: 167
Quote:
Originally Posted by MK27 View Post
The problem is not that you use fgets. The problem is that you use fgets at the end of the while loop. select can be made to check for input from a file descriptor and, if there is none, move on. But fgets cannot. If you call fgets, it is going to wait for input.

I'm no pro, I don't use windows, and I just started with c in the summer, but I have written an ncurses forking (local socket) server and client which works well (you can send messages back and forth without this problem, etc). Unfortunately, I haven't gotten into pthreads yet, so I'm not sure of the syntax, but logically YOU MUST seperate the process which waits for input from the socket from the process which waits for input locally. With fork, this means you have the child in the server monitoring connected sockets via select, while the parent waits for keyboard input and sends it. With pthreads, I suspect you must use seperate function calls. Hopefully someone out there can fill in the gaps for us.

The key point: once you call fgets, or scanf, or whatever you want to use for local input, that command is going to wait until there is local input, and nothing else will happen. You have to use seperate, parallel loops.

If you don't have much experience with pthreads you should use fork until you get this working. I found the use of sockets for inter-process communication very tricky, relatively speaking, and I suspect you still have a long way to go but you are getting there.
Ok so I took your advice and started researching some fork() stuff. I found this page which had a little example on it: http://www.linuxhowtos.org/C_C++/socket.htm

So I made the modifications to my program exactly like the page above. It compiles and runs just fine, but unfortunately, it seems it didn't make any difference at all.

Am I doing it wrong?

Here's what I did:

Code:
//Client
		if (command == 1)
		{
			while(input[0] != 'E' || input[1] != 'X' || input[2] != 'I' || input[3] != 'T')
			{
				int pid = fork();
				if (pid < 0)
					perror("fork error");
				if (pid == 0)
				{
					fgets(input, 100, stdin);
					if (send(sock, input, sizeof(input), 0) == -1)
						perror("send error");
				}

				if(( received = recv(sock,buffer,BUFFSIZE-1, 0)) < 0 )
				{
					perror("Failed to receive additional bytes from client \n");
				}
				if(received >0)
				{
					printf("Received from Server : %s",buffer);
				}
			}
		}
Code:
//Server
	while(1)
	{
		int pid;
		FD_ZERO(&fds);
		FD_SET(sock,&fds);

		nready = select(maxfd,&fds,0,0,0);
		if(FD_ISSET(sock,&fds))
		{
			if(( received = recv(sock,buffer,BUFFSIZE-1, 0)) <0 )
			{
				perror("Failed to receive additional bytes from client \n");
			}
			if(received >0)
			{
				printf("Received from Client : %s",buffer);
			}
			if(received < 1)
			{
				printf("Closing this client\n");
				close(sock);
				pthread_exit(NULL);
			}
			memset(buffer,0,sizeof(buffer)); // V, 0
		}

		pid = fork();
		if (pid < 0)
			perror("fork error");
		if (pid == 0)
		{
			fgets(input, 100, stdin);
			if (send(sock, input, sizeof(input), 0) == -1)
				perror("send error");
		}
	}
Paul22000 is offline   Reply With Quote
Old 11-12-2008, 03:27 AM   #6
mastering the obvious
 
MK27's Avatar
 
Join Date: Jul 2008
Location: SE Queens
Posts: 5,071
First off, you are using fork kind of wrong, but bare with me a minute...

You are using linux, great. You can look at my ncurses local socket version:

http://www.intergate.com/~halfcountp...t_ncurses.html
the header is http://www.intergate.com/~halfcountp...de/c/mine.html

The server actually doesn't use fork because it uses the ncurses main loop, but the client does (the client isn't ncurses).and a simpler single command line program:

http://www.intergate.com/~halfcountp...al-socket.html
may be better to look at and doesn't require the header but it's one program instead of a seperate client/server.

but really these are similar to many examples that are available on the web already, so I won't get nitty gritty about how they work unless you ask a specific question I may be online for another hour or so and again tomorrow.

Anyway, the deal with fork is that after the call you need two or three ifs: one (sort of optional) to check for an error, but then one (==0, the child) to do the socket or input check
and THEN ANOTHER ONE (==pid) which is the parent to do the parallel operation. The way you have it, fork is inside a while (1) loop. You should have the while loop inside the fork instead.

Like I said, getting it all to work seemed very frustrating.
__________________

“The essential element in the black art of obscurantism is not that it wants to darken individual understanding, but that it wants to blacken our picture of the world, and darken our idea of existence.” [Friedrich Wilhelm Nietzsche, 1878]

Last edited by MK27; 11-12-2008 at 03:31 AM.
MK27 is online now   Reply With Quote
Old 11-12-2008, 10:19 AM   #7
Registered User
 
valaris's Avatar
 
Join Date: Jun 2008
Location: RING 0
Posts: 468
fork() returns twice. Once in the parent and once in the child. So if fork returns 0 you are in the child process that is now competing for a time slice of a CPU. Greater then zero will be the parent. So these two blocks are executing "concurrently", or at least appearing to.
valaris is offline   Reply With Quote
Old 11-12-2008, 10:24 AM   #8
Registered User
 
valaris's Avatar
 
Join Date: Jun 2008
Location: RING 0
Posts: 468
It could if you have multiple processors. Otherwise it competes for a time quantum to execute on. To a user though this could appear as working concurrently. No a while loop wont effect your fork(). It's a seperate process just like the original program you executed was a process. You can do anything with it .

In fact in *nix essentially everytime you init a new program a new process is forked from the shell.
valaris is offline   Reply With Quote
Old 11-12-2008, 11:33 AM   #9
Registered User
 
valaris's Avatar
 
Join Date: Jun 2008
Location: RING 0
Posts: 468
Be wary that you get input and send it before you backwardsly check for exit. Consider strcmp(). Also you only try and recv once, everytime command == 1.
valaris is offline   Reply With Quote
Old 02-10-2009, 12:35 AM   #10
Registered User
 
Join Date: Feb 2009
Location: Philippines
Posts: 3
hello!
Thanks for the advice, MK27! what i'm worrying is that i'm running out of time in studying ncurses..But i guess i should try my best to learn it for a short period of time..

I've tried compiling your code in http://www.intergate.com/~halfcountp...de/c/mine.html, but there's an error such as "undefine reference....

what i did is use..."gcc -o m mine.c -lncurses" in compiling where i am wrong?

can u provide me with sample code showing the txt I inputted from one window then showing the text i input in other window...I'll start studying with your sample I guess.

THANKS !
laena is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Program Plan Programmer_P C++ Programming 0 05-11-2009 01:42 AM
my server program auto shut down hanhao Networking/Device Communication 1 03-13-2004 10:49 PM
insufficient memory for tsr manmohan C Programming 8 01-02-2004 09:48 AM
Date program starts DOS's date jrahhali C++ Programming 1 11-24-2003 05:23 PM
My program, anyhelp @licomb C Programming 14 08-14-2001 10:04 PM


All times are GMT -6. The time now is 12:36 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22