LinuxQuestions.org
View the Most Wanted LQ Wiki articles.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 09-11-2011, 02:10 AM   #1
silentkill89
LQ Newbie
 
Registered: Aug 2011
Posts: 28

Rep: Reputation: Disabled
[question] a tcp server and client program


As topic, I want writing a client and server program that server would receive connection from client and respond appropriate message to client. What i already is client would send whatever message including number string to the server and the server will send back to client of what exactly it receive. With the sequence above, I want to create 1 more feature, which is when the client send a string of integer number, for example: 1234567 to the server. The server will automatically compute this string of number and send back the compute answer to the client. Lets say i want the answer to be display like this:
- Client: 1234567
- Server compute and send to client
Client display : 28
Client display: 10
Client display : 1

The first answer, which is 28 is adding the intergers 1+2+3+4+5+6+7 = 28
The second will be 2+8 = 10
The third will be 1+0 = 1
When the numbers reach a single digit,for example like : 1 from the above, the server will stop sending answer and wait for next message to receive.
Is there any idea of calculating the string of numbers in that way?
Kindly attach some code example if necessary, thank you
Here's my code

Code:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

#define MAXLINE 4096 /*max text line length*/
#define SERV_PORT 3000 /*port*/
#define LISTENQ 8 /*maximum number of client connections */

int main (int argc, char **argv)
{
 int listenfd, connfd, n;
 pid_t childpid;
 socklen_t clilen;
 char buf[MAXLINE];
 struct sockaddr_in cliaddr, servaddr;
	
 //creation of the socket
 listenfd = socket (AF_INET, SOCK_STREAM, 0);
	
 //preparation of the socket address 
 servaddr.sin_family = AF_INET;
 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 servaddr.sin_port = htons(SERV_PORT);
	
 bind (listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
	
 listen (listenfd, LISTENQ);
	
 printf("%s\n","Server running...waiting for connections.");
	
 for ( ; ; ) {
		
  clilen = sizeof(cliaddr);
  connfd = accept (listenfd, (struct sockaddr *) &cliaddr, &clilen);
  printf("%s\n","Received request...");
				
  while ( (n = recv(connfd, buf, MAXLINE,0)) > 0)  {
   printf("%s","String received from and resent to the client:");
   puts(buf);
   send(connfd, buf, n, 0);
  }
			
 if (n < 0) {
  perror("Read error"); 
  exit(1);
 }
 close(connfd);
	
 }
 //close listening socket
 close (listenfd); 
}
Code:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

#define MAXLINE 4096 /*max text line length*/
#define SERV_PORT 3000 /*port*/

int
main(int argc, char **argv) 
{
 int sockfd;
 struct sockaddr_in servaddr;
 char sendline[MAXLINE], recvline[MAXLINE];
	
 //basic check of the arguments
 //additional checks can be inserted
 if (argc !=2) {
  perror("Usage: TCPClient <IP address of the server"); 
  exit(1);
 }
	
 //Create a socket for the client
 //If sockfd<0 there was an error in the creation of the socket
 if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) <0) {
  perror("Problem in creating the socket");
  exit(2);
 }
	
 //Creation of the socket
 memset(&servaddr, 0, sizeof(servaddr));
 servaddr.sin_family = AF_INET;
 servaddr.sin_addr.s_addr= inet_addr(argv[1]);
 servaddr.sin_port =  htons(SERV_PORT); //convert to big-endian order
	
 //Connection of the client to the socket 
 if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0) {
  perror("Problem in connecting to the server");
  exit(3);
 }
	
 while (fgets(sendline, MAXLINE, stdin) != NULL) {
	
  send(sockfd, sendline, strlen(sendline), 0);
		
  if (recv(sockfd, recvline, MAXLINE,0) == 0){
   //error: server terminated prematurely
   perror("The server terminated prematurely"); 
   exit(4);
  }
  printf("%s", "String received from the server: ");
  fputs(recvline, stdout);
 }

 exit(0);
}
 
Old 09-11-2011, 04:54 AM   #2
silentkill89
LQ Newbie
 
Registered: Aug 2011
Posts: 28

Original Poster
Rep: Reputation: Disabled
does anyone know how the methods? Please help me in urgent..thanks
 
Old 09-11-2011, 06:52 AM   #3
silentkill89
LQ Newbie
 
Registered: Aug 2011
Posts: 28

Original Poster
Rep: Reputation: Disabled
128 viewers but no one gonna answer ;(
 
Old 09-11-2011, 08:19 AM   #4
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942
There are lots of people interested in TCP/IP client-server programming, but your intent seems strange. Strange enough to look like homework, so many will just skip the thread after the first few lines.

Here is a bit of server code. While it works, it is quite badly designed -- intentionally so; while it works, it is not the way I'd personally do it. I hope that this will give you a small boost in your own efforts.
Code:
#define  _BSD_SOURCE
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>

#define   PORT		3000
#define   BACKLOG	8

unsigned int sum_digits_in(const void *const data, const size_t length)
{
	const char *const string = (const char *const)data;
	size_t		  index = length;
	unsigned int      result = 0U;

	while (index-->0)
		if (string[index] >= '0' && string[index] <= '9')
			result += string[index] - '0';

	return result;
}

unsigned int sum_digits(const unsigned int value)
{
	unsigned int digits = value;
	unsigned int result = 0U;

	while (digits) {
		result += digits % 10U;
		digits /= 10U;
	}

	if (result == value)
		return 0U;

	return result;
}

int main()
{
	int			socketfd, descriptor;
	struct sockaddr_in	remote, local;
	socklen_t		remote_len;

	char			request[4096];
	char			response[1024]; /* Actually ~ 30 max. used */

	char			client[1024];

	unsigned int		value;
	int			size, n, i;
	ssize_t			bytes;



	socketfd = socket(AF_INET, SOCK_STREAM, 0);
	if (socketfd == -1) {
		fprintf(stderr, "Cannot create socket: %s.\n", strerror(errno));
		return 1;
	}

	local.sin_family = AF_INET;
	local.sin_addr.s_addr = INADDR_ANY;
	local.sin_port = htons(PORT);
	if (bind(socketfd, (struct sockaddr *)&local, (socklen_t)sizeof(struct sockaddr_in)) == -1) {
		fprintf(stderr, "Cannot bind to port %d: %s.\n", PORT, strerror(errno));
		return 1;
	}

	if (listen(socketfd, BACKLOG) == -1) {
		fprintf(stderr, "Cannot listen: %s.\n", strerror(errno));
		return 1;
	}

	while (1) {

		remote_len = sizeof(struct sockaddr_in);
		descriptor = accept(socketfd, (struct sockaddr *)&remote, &remote_len);
		if (descriptor == -1) {
			if (errno == EINTR || errno == EAGAIN)
				continue;

			fprintf(stderr, "Error in an incoming connection: %s.\n", strerror(errno));
			return 1;
		}

		if (!inet_ntop(AF_INET, &remote.sin_addr, client, sizeof(client) - 1)) {
			client[0] = '?';
			client[1] = 0;
		}

	more:

		bytes = read(descriptor, request, sizeof(request));
		if (bytes == (ssize_t)0) {

			fprintf(stderr, "%s: Disconnected, bye bye!\n", client);
			fflush(stderr);

			close(descriptor);
			continue;
		}
		if (bytes < (ssize_t)0) {
			const char *const errmsg = (bytes == (ssize_t)-1) ? strerror(errno) : "Disconnected";

			fprintf(stderr, "%s: %s.\n", client, errmsg);
			fflush(stderr);

			close(descriptor);
			continue;
		}

		fprintf(stderr, "%s: %d bytes requested.\n", client, (int)bytes);
		fflush(stderr);

		value = sum_digits_in(request, (size_t)bytes);

		if (!value) {

			fprintf(stderr, "%s: No data. Bye bye!\n", client);
			fflush(stderr);

			close(descriptor);
			continue;
		}

		size = 0;
		do {
			n = snprintf(response + size, sizeof(response) - 1 - size, "%u\n", value);
			if (n < 1) {
				/* Should never happen. */
				size = 0;
				break;
			}

			size += n;
			value = sum_digits(value);
		} while (value);

		fprintf(stderr, "%s: Sending '", client);
		for (i = 0; i < size; i++)
			fputc( (response[i]>='0' && response[i]<='9') ? response[i] : ' ', stderr);
		fprintf(stderr, "' (%d bytes).\n", size);
		fflush(stderr);

		/* Send the response string. */
		if (size > 0) {
			const char        *p = response;
			const char *const  q = response + size;

			while (p < q) {
				bytes = write(descriptor, p, (size_t)(q - p));
				if (bytes > (ssize_t)0)
					p += bytes;
				else
				if (bytes != -1 || errno != EINTR)
					break;
			}

			n = (int)(p - response);
		} else
			n = 0;

		/* Everything OK to continue? */
		if (n == size && size > 0)
			goto more;

		fprintf(stderr, "%s: Sent only %d of %d bytes. Closing connection.\n", client, n, size);
		fflush(stderr);

		close(descriptor);
	}

	/* Never reached. */
	close(socketfd);
	return 127;
}
The program will bind to the wildcard address, port 3000, so it will accept connections on any IP address the machine owns. You can use for example telnet as the client.

If you save the above as digit-server.c you can compile and run it using
Code:
gcc -Wall -O3 -o digit-server digit-server.c
./digit-server
Then, in another terminal on the same machine, run
Code:
telnet 127.0.0.1 3000
Telnet will send each completed line, so type some numbers (the server will ignore everything except digits), and press enter to send the line to the server. The server will close the connection if you supply an empty line (anything without any digits in it). You can of course also close telnet or the terminal you're running telnet in; the server will detect and handle that too. (I don't think it notices if a remote machine crashes suddenly while communicating; I think it stays waiting for input for a long time.)

You could write a client for the above service, too, although just about any TCP/IP-based client works. Here is a command-line client written in Bash:
Code:
#!/bin/bash
[ -n "$SERVER" ] || SERVER=127.0.0.1
[ -n "$PORT"   ] || PORT=3000

if [ $# -gt 0 ]; then
	while [ $# -gt 0 ]; do
		echo "$1 = "
		exec 3<>/dev/tcp/$SERVER/$PORT
		echo "$1" >&3
		shift 1
		while read -t 0.1 LINE <&3 ; do
			echo "	$LINE"
		done
		exec 3<&-
	done
else
	echo 'Enter an empty line to quit.' >&2
	while read -p '? ' INPUT ; do
		[ -n "$INPUT" ] || exit 0
		exec 3<>/dev/tcp/$SERVER/$PORT
		echo "$INPUT" >&3
		while read -t 0.1 LINE <&3 ; do
			echo "	$LINE"
		done
		exec 3<&-
	done
fi

Last edited by Nominal Animal; 09-11-2011 at 09:43 AM. Reason: Added compiling and running instructions, and a Bash client.
 
Old 09-11-2011, 08:56 AM   #5
silentkill89
LQ Newbie
 
Registered: Aug 2011
Posts: 28

Original Poster
Rep: Reputation: Disabled
it's not a homework, it was a program that i created before but I wish to modify after one of my friend has inspired of his program which could compute the price of product when the client send the product ID to server.

Back to topic, the code you gave me is a server side, but how about the client side? or is a standalone program? Also may I know how to run your program? You did not explain clearly of executing it, whether is with ip or port. Sorry for disturbance
 
Old 09-11-2011, 10:30 AM   #6
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942
Quote:
Originally Posted by silentkill89 View Post
Back to topic, the code you gave me is a server side, but how about the client side?
I added an example Bash client. You can run that either by specifying the numbers on the command line, or by interactively typing.

Something like this is usually written on top of HTTP. If you format the messages in XML, you can interface to it in a lot of different ways; for example, you can write a bit of Javascript on a web page, and access it from that script (interactively, no need to reload anything). Or you can format the message in say Python or PHP, do a query using the HTTP facilities available in those languages, and parse the XML message. A protocol similar to
Code:
Request format:
	<?xml version="1.0"?>
	<request>1234567</request>

Response format:
	<?xml version="1.0"?>
	<response>
		<value>28</value>
		<value>10</value>
		<value>1</value>
	</response>
is extremely easy to handle in different languages and environments, and you can even extend the format while maintaining backwards compatibility, if you design it carefully. To do stuff like this, learn CGI, FastCGI, WSGI to do it directly on top of a good HTTP server (Apache, nginx, LigHTTPD, for example), or use one of the frameworks. For this level of things, maintainability, adaptability, ease of development, reliability and so on are much more important than lower-level implementation details.

Dropping down to the socket level is really only warranted if there is an actual reason. Of course, learning stuff is a very good reason. As is doing stuff just for fun. But your questions have straddled two totally different areas -- simple services, and hard-core low-level socket I/O --, which is a bit jarring. There is nothing wrong in either, it is just that not many are used to working with them at the same time. (I suspect this is the primary reason others have not chipped in.)

I suggest you might find it better worth your time to split these areas for now, and develop them separately. Client-server exercises are much more fun with higher level languages. (I am talking about mental exercises, not homework, by the way.) Designing and trying out different ways to communicate -- and seeing the results immediately in your browser is much more rewarding in the short term.

On the socket level, you may find that transferring binary data (properly formatted) is actually easier in C than all the stringy stuff. Plain C does not have much in the way of string handling, so most of the examples I've seen just skip the important bits (error handling, dynamic memory management, and so on), and do "something" with sockets to show how it is "in principle" done. Having two programs talk to each other without any human intervention is also a good idea; humans just make things more difficult anyway. Experiment!
 
Old 09-11-2011, 12:05 PM   #7
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
I suggest you first write a program that has the desired behavior using standard input and output to simulate interacting with a client. After that it's trivial to make it work over a socket, and setting up the socket is largely independent of the task itself. You really have two problems to solve:
  1. Create a line-based program that will read lines of digits. For each line it will perform an uncertain number of operations, writing one line per operation. The finality of the last operation is predictable (i.e. both ends know that 1 digit means "done").
  2. Create a client/server pair that communicate one line at a time via a socket.
Both of these can and should be developed separately. In fact, it wouldn't be uncommon in the second program above to fork when a new connection is made, replace standard input and output of the child with the socket, then execvp the first program. This is essentially the task inetd performs.
Kevin Barry
 
Old 09-11-2011, 12:15 PM   #8
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by Nominal Animal View Post
On the socket level, you may find that transferring binary data (properly formatted) is actually easier in C than all the stringy stuff.
One problem with switching to binary is you can't use any FILE* functions like fgets. That means if you're reading delimited input where the data segments aren't of predictable length you have to implement your own buffering system to compensate for reading more than is needed. The other alternative is to read a character at a time. With proper binary data, e.g. C-structs, you can run into problems with width, alignment, and endianness. In my experience, you might as well use C++ or flex/bison if you're dealing with text from read, and binary data needs some sort of protocol (or file format) design.
Kevin Barry
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[Question] tcp client and server connection problems silentkill89 Programming 6 09-04-2011 08:27 PM
[QUestion] tcp client and server silentkill89 Programming 5 09-04-2011 01:54 PM
qt tcp client, C tcp server deadeyes Programming 3 09-04-2011 10:23 AM
How can I handover Stdin/Stdout Operations over TCP to a client initiated program? humandynamo Linux - Software 2 01-27-2009 01:57 PM


All times are GMT -5. The time now is 03:20 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration