Solved

Socket Programming (Unix)

Posted on 2016-07-27
8
171 Views
Last Modified: 2016-07-31
Dear Experts,

I have a code socket server, listen on TCP port 8888.
I use top command, it will see that actually used memory grows each time a new connection is accepted while it is not released after the thread finishes its work.

Test.c

#include<stdio.h>
#include<string.h>    //strlen
#include<stdlib.h>    //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h>    //write

#include<pthread.h> //for threading , link with lpthread

void *connection_handler(void *);

int main(int argc, char *argv[]) {
	int socket_desc, new_socket, c, *new_sock;
	struct sockaddr_in server, client;

	//Create socket
	socket_desc = socket(AF_INET, SOCK_STREAM, 0);
	if (socket_desc == -1) {
		printf("Could not create socket");
	}

	//Prepare the sockaddr_in structure
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = INADDR_ANY;
	server.sin_port = htons(8888);

	//Bind
	if (bind(socket_desc, (struct sockaddr *) &server, sizeof(server)) < 0) {
		puts("bind failed");
		return 1;
	}
	puts("bind done");

	//Listen
	listen(socket_desc, 3);

	//Accept and incoming connection
	puts("Waiting for incoming connections...");
	c = sizeof(struct sockaddr_in);
	while ((new_socket = accept(socket_desc, (struct sockaddr *) &client,
			(socklen_t*) &c))) {
		puts("Connection accepted");

		pthread_t sniffer_thread;
		new_sock = (int*) malloc(sizeof(int));
		*new_sock = new_socket;

		if (pthread_create(&sniffer_thread, NULL, connection_handler,
				(void*) new_sock) < 0) {
			perror("could not create thread");
			return 1;
		}

		//Now join the thread , so that we dont terminate before the thread
		//pthread_join( sniffer_thread , NULL);
		puts("Handler assigned");
	}

	if (new_socket < 0) {
		perror("accept failed");
		return 1;
	}

	return 0;
}

/*
 * This will handle connection for each client
 * */
void *connection_handler(void *socket_desc) {
	//Get the socket descriptor
	int sock = *(int*) socket_desc;
	int read_size;
	char client_message[2000];

	struct timeval tv;
	tv.tv_sec = 3; /* Timeout in seconds */
	setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (struct timeval *) &tv,
			sizeof(struct timeval));
	setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *) &tv,
			sizeof(struct timeval));

	read_size = recv(sock, client_message, 100, 0);
	client_message[read_size] = '\0';

	printf("CLIENT SEND>%s<\n", client_message);

	write(sock , client_message , strlen(client_message));

	//Free the socket pointer
	free(socket_desc);
	close(sock);
	pthread_exit(NULL);

Open in new window

Build:
gcc -lpthread Test.c -o Test

Help me, please.
Thanks.
0
Comment
Question by:ldvhai
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 2
8 Comments
 
LVL 36

Expert Comment

by:mccarl
ID: 41732253
I use top command, it will see that actually used memory grows each time a new connection is accepted while it is not released after the thread finishes its work

The main thing I would say is to be careful assuming that you have a memory leak just by looking at top. It could very well be that the memory IS being released, it is just that next memory allocation isn't necessarily using previously released memory. Perhaps, it is only when memory resource are close to exhausted that it goes back and starts using previously freed memory.

The other point that I would make is that you should be able to get rid of the malloc/free calls in the above code, because the sizeof(void*) should be big enough to hold your int, so you could do this...

#include<stdio.h>
#include<string.h>    //strlen
#include<stdlib.h>    //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h>    //write

#include<pthread.h> //for threading , link with lpthread

void *connection_handler(void *);

int main(int argc, char *argv[]) {
	int socket_desc, new_socket, c, *new_sock;
	struct sockaddr_in server, client;

	//Create socket
	socket_desc = socket(AF_INET, SOCK_STREAM, 0);
	if (socket_desc == -1) {
		printf("Could not create socket");
	}

	//Prepare the sockaddr_in structure
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = INADDR_ANY;
	server.sin_port = htons(8888);

	//Bind
	if (bind(socket_desc, (struct sockaddr *) &server, sizeof(server)) < 0) {
		puts("bind failed");
		return 1;
	}
	puts("bind done");

	//Listen
	listen(socket_desc, 3);

	//Accept and incoming connection
	puts("Waiting for incoming connections...");
	c = sizeof(struct sockaddr_in);
	while ((new_socket = accept(socket_desc, (struct sockaddr *) &client,
			(socklen_t*) &c))) {
		puts("Connection accepted");

		pthread_t sniffer_thread;

		if (pthread_create(&sniffer_thread, NULL, connection_handler,
				(void*) new_socket) < 0) {
			perror("could not create thread");
			return 1;
		}

		//Now join the thread , so that we dont terminate before the thread
		//pthread_join( sniffer_thread , NULL);
		puts("Handler assigned");
	}

	if (new_socket < 0) {
		perror("accept failed");
		return 1;
	}

	return 0;
}

/*
 * This will handle connection for each client
 * */
void *connection_handler(void *socket_desc) {
	//Get the socket descriptor
	int sock = (int) socket_desc;
	int read_size;
	char client_message[2000];

	struct timeval tv;
	tv.tv_sec = 3; /* Timeout in seconds */
	setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (struct timeval *) &tv,
			sizeof(struct timeval));
	setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *) &tv,
			sizeof(struct timeval));

	read_size = recv(sock, client_message, 100, 0);
	client_message[read_size] = '\0';

	printf("CLIENT SEND>%s<\n", client_message);

	write(sock , client_message , strlen(client_message));

	close(sock);
	pthread_exit(NULL);

Open in new window

1
 
LVL 2

Author Comment

by:ldvhai
ID: 41732319
Hi mccarl,

Thanks for your answer.

I run your code, but memory grows each time a new connection is accepted while it is not released after the thread finishes its work.

1)      Do not run Test
 1.png2)      Run Test, Do not send request to Port 8888
 2.png
3)      Send 1000 request to Port 8888
Command:
# for i in {1..1000};do echo -n ${i} "---> ";echo -n "TEST_RAM" | nc localhost 8888;echo "";sleep 0.005;done
•      RAM info which 1000 connection.
 3.png
 4.png•      RAM info when connection release, only server listen port 8888
 5.png 6.png4)      Exit Test
 7.png
0
 
LVL 36

Expert Comment

by:mccarl
ID: 41732362
As I said previously, you can't look at those numbers and assume that the memory is NOT being released.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 2

Author Comment

by:ldvhai
ID: 41732560
Hi mccarl,

Thanks for your answer.
I send unlimited requests to the server
After a period of time , used memory grows and Test program dead.
Thus, this program does not release memory.

Is it right?

Help me, please.
Thanks.
0
 
LVL 34

Accepted Solution

by:
sarabande earned 500 total points
ID: 41732964
to add to previous comments:

you may try to comment pthread_exit call. the thread would terminate at return  anyhow. pthread_exit wouldn't release resources of the main thread regarding this thread. this is not small if you have build in debug mode. you also could/should try to call pthread_attr_destroy within the thread since even the 'attr' argument was NULL at pthread_create. a default attribute resource was created nevertheless.

also note that the tcp/ip subsystem is running asynchronously. hence after the recv the tcp still holds buffers and resources especially if the client would not close and shutdown immediately after send.

actually each of your threads should not end before the connection to their clients was not orderly run to shutdown. i would say you need at least to wait 10 seconds before you could terminate the thread with return to make sure that the resources used for the connection could be freed since both sides were down.

in any case if you have a debug build all memory measurements are waste since the debugger will not spare memory allocated but adds some debug space to each allocation which later could prevent from memory to be reused since it was defragmented.

Sara
1
 
LVL 2

Author Comment

by:ldvhai
ID: 41736949
Hi sarabande,

Thanks for your answer.
You can edit code for me with pthread_attr_destroy, please.


Thanks.
0
 
LVL 2

Author Comment

by:ldvhai
ID: 41736996
Hi sarabande,

I fixed success.

Thank you very much.
0
 
LVL 2

Author Closing Comment

by:ldvhai
ID: 41736998
I fixed by pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

Thanks.
1

Featured Post

[Webinar] How Hackers Steal Your Credentials

Do You Know How Hackers Steal Your Credentials? Join us and Skyport Systems to learn how hackers steal your credentials and why Active Directory must be secure to stop them. Thursday, July 13, 2017 10:00 A.M. PDT

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…

691 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question