server obiektowo c++ 11 thread

0

Hej mam problem, chcę napisać server obiektowo w standardzie c++ 11. Jednak przeszkada jest wywolanie tworzenia wątku i funkcja która miałaby taki wątek obsłużyć..

Nagłówkowy klasy wygląda tak:

 
/*
 * server.h
 *
 *  Created on: 10 sie 2015
 *      Author: michal
 */

#ifndef SERVER_H_
#define SERVER_H_
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>



class tcp_server
{
private:
	int sock;
	static int socket_thread;
	int port;
	struct sockaddr_in server_addr;
public:
    tcp_server();
	~tcp_server();
	void bind_(int port);
	void listen_();
	int accept_();
	void create_thread();
	void funkcja();
};


#endif /* SERVER_H_ */

A metody tak:

#include "server.h"
#include "struktury.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <cstdio>
#include <string.h>  // memset()
#include <unistd.h>  // close()
#include <thread>


tcp_server::tcp_server()
{
	if((sock=socket(AF_INET,SOCK_STREAM,0))<0)
	{
		perror("socket error ");
	}
	port = 8888;
}

tcp_server::~tcp_server()
{
	close(sock);
}

void tcp_server::bind_(int port)
{
	memset(&server_addr,0,sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	if((bind(sock,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)))<0)
	{
		close(sock);
		perror("bing error");
	}
}

void tcp_server::listen_()
{
	if((listen(sock,5))<0)
	{
		perror("listen error");
	}
}

int tcp_server::accept_()
{
	int new_connect;
	fd_set rfds;
	struct timeval tv;
	int maxfd;
	FD_ZERO(&rfds);
	FD_SET(this->sock,&rfds);
	tv.tv_sec = 0;
	tv.tv_usec = 50000;
	maxfd = sock;

	if(select(maxfd+1,&rfds,NULL,NULL,&tv)>0)
	{
		socklen_t laddr_len = sizeof(sockaddr);
		if((new_connect = accept(sock, (struct sockaddr*)&server_addr,&laddr_len))<0)
		{
			perror("accept error");
		}
		this->socket_thread = new_connect;
		return new_connect;
	}
return 0;
}

void tcp_server::create_thread()
{
	std::thread t(&funkcja);
	t.detach();
}

void tcp_server::funkcja()
{
	char msg[512];
	int my_socket=socket_thread;
	fd_set rfds;
	struct timeval tv;
	int retval,maxfd;
	FD_ZERO(&rfds);
	FD_SET(my_socket,&rfds);
	tv.tv_sec=0;
	tv.tv_usec= 50000;
	maxfd=my_socket;
	int read_size,score;
//	----------------------------------
	 connect_req con_req;
	 connect_rsp con_rsp;
	 disconnect_req disc_req;
	 disconnect_rsp dis_con_rsp;
//	 ----------------------------------
	while(1)
	{
		puts("czelam na polaczenie");
		retval = select(maxfd+1,&rfds,NULL,NULL,&tv);
		if(retval>0)
     	{
			memset(msg,'\0',sizeof(msg));
	      	read_size = recv(my_socket,msg,512,0);
	      	if(read_size==0)
	      	{
	      		puts("client disconnected");
	      		fflush(stdout);
	      		close(my_socket);
	      		//~thread(); // destruktor watku
	      	}
	      	else if(read_size<0)
	      	{
	      		perror("recv failed*");
	      	}
	      	score = *((uint16_t *)&msg[ 0 ]);
	      	score = ntohs(score);
	      	switch(score)
	      	{
	        	case 1:
	      		{
	      		    con_req.deserializuj(msg);
	      			cout<<"Case0: "<<endl;
	      			cout<<"Code: "<<con_req.code<<endl;
	      			cout<<"Length: "<<con_req.length<<endl;
	      			cout<<"Message: "<<con_req.name;

	      			con_rsp.code = 0x0003;
	      			con_rsp.length = 0x0000;
	      			con_rsp.status = 144;
	      			char *q=con_rsp.serializuj();
	      			if(send(my_socket,q,sizeof(q),0)<0)
	      			{
	      			   puts("Send failed server_con_rsponse");
	      			   return;
	      			 }
	      		     delete [] q;
	      		   break;
	      		 }
	      		 case 3:
	      		 {
	      			break;
	      		 }
	      		 case 4:
	      		 {
	      		     disc_req.deserializuj(msg);
	      			 cout<<"Case4: "<<endl;
	      			 cout<<"Code: "<<disc_req.code<<endl;
	      			 cout<<"Lenhth: "<<disc_req.length<<endl;

	      			 dis_con_rsp.code = 0x0004;
	      			 dis_con_rsp.length = 0x0007;
	      			 dis_con_rsp.status = 97;
	      			 char* l=dis_con_rsp.serializuj();
	      			 if(send(my_socket,l,6,0)<0)
	      			 {
	      			     puts("Send failed");
	      			 }
	      			 cout<<"weszlo jak w maslo";
	      			 break;
	      		   }
	      		  case 5:
	      		  {
	      		      con_req.deserializuj(msg);
	      			  cout<<"Case5: "<<endl;
	      			  cout<<"Code: "<<con_req.code<<endl;
	      			  cout<<"Length: "<<con_req.length<<endl;
	      			  cout<<"Message: "<<con_req.name;

	      			  con_rsp.code = 0x0003;
	      			  con_rsp.length = 0x0000;
	      			  con_rsp.status = 144;
	      			  char *o=con_rsp.serializuj();
	      			  if(send(my_socket,o,sizeof(o),0)<0)
	      			  {
	      			      puts("Send failed server_con_rsponse");
	      				  return;
	      			  }
	      				delete [] o;
	      			  }
	      				break;
	      			default:
	      			{
	      				cout<<"brak dzialania";
	      			}
	      			break;
	      		}//switch

	      	}//retval>0
		tv.tv_sec = 0;
		tv.tv_usec=50000;
		FD_ZERO(&rfds);
		FD_SET(my_socket,&rfds);
     	}//while

	close(my_socket);
	return;
}//tcp funkcja
 

dołaczony jest jeszcze do tego plik struktury.h w którym zawarte sa metody serializacji i desarlizacji. Główny problem stanowi metoda void tcp_server::create_thread() z której to chcę wywołać metodę void tcp_server::funkcja(). Za wszelkie informacje i porady serdecznie dziękuję!

 
0

Użyj std::bind, lamby albo funktora, albo jeszcze czegoś o czym nie wiem.
Tu przykład z bindem i lambdą https://ideone.com/ABF2IC

EDIT
na potrzeby tego programu uzyłem thread.join zamiast thread.detach

0

a mógłbys dokładniej opisac działanie funkcji bind? oraz powiedziec mi jak wywolac tą funkcje z argumentami przekazanymi do funkcji create_thread oraz funkcja?

0

Nie wytłumaczę tego lepiej niż jest tu http://en.cppreference.com/w/cpp/utility/functional/bind
Masz tam też przykłady z parametrami

0
 
void tcp_server::create_thread(int my_socket)
{
//	auto f = std::bind(&tcp_server::funkcja,my_socket);
	auto f2 = [this](){funkcja(my_socket);};
	std::thread t(f2);
	t.detach();
}

void tcp_server::funkcja(int my_socket)

zmienilem funkcje teraz przyjmuja argumenty i dostaje blad..
error 'my_socket' is not captured

1
auto f2 = [this, &my_socket](){funkcja(my_socket);};

(:

0

wszystko byloby dobrze ale my_socket przekazany do create_thred jest rowny 4, ale juz w wywolaniu funkcji: funkcja ma wartosc 0.

	auto f2 = [this, &my_socket](){funkcja(my_socket);};
	cout<<"wywolanie my_scoket po thread create"<<my_socket<<endl;
	std::thread t(f2);
	t.detach();
 

tutaj niby coutem wyswietla dobrze przekazany deskryptor ale jak w funkcji funkcja(int my_socket) chce wypisać deskrypto
wyswietla mi 0.

1

Masz rację. Lipę odstawiłem. Takie coś będzie ok

auto f2 = [this](int my_sock){funkcja(my_sock);};
std::thread t(f2, my_socket);
0

a może ktos nakierucje mnie jeszcze jak zrobic zeby po sygnale ctl + c serwer wyslaw do wszyskich clientow informacje ze jest zamykany (czekal na informacje zwrotna) po czym zamykal wszystkie watki i konczyl dzialanie?? no i podobnie w clientcie :)
czy to obsluguje sie gdzies w select na 4 pozycji czy moze jakos trzeba zrobic sigaction??

1
 
static void sigint_func(int signo) {
    puts("sigint\n");
    //wysylasz
}

int main(void) {
    if (signal(SIGINT, sigint_func) == SIG_ERR)
        return EXIT_FAILURE;
 }
0

Wszystko ok ale chce przekazac ta informacje do kazdego z klientow ( czyt. do kazdego watku ) zeby rozeslal ramke konczaca poczekal na odpowiedz od wszyskich kliento a pozniej zakonczyl glowny watek :)

0

No to przekazujesz do std::signal tak napisaną metodę. W czym problem?

0

Może nie tyle "rozesłać informację" co ustawić flagę (bezpiecznie wielowątkowo) że jest przerwanie działania wątków i sprawdzać ją w bezpiecznym wielowątkowo momencie działania Twojej aplikacji. W C++ 11, implementacja nie posiada interrupt() które mogło by być naturalne w takim przypadku (boost ma).
Flagą może być także wspólna blokada jeśli sprawdzasz ją "nieblokująco" (try_lock()).

0

dodałem zmienna globalna info, gdy zmienna ta != 0 wtedy do whila w funkcji wykorzystywanej przez watek dodalem nastepujacego ifa

 
		if(info!=0)
		{
			while(1)
			    {
				disc_req.code = 0x0004;
				disc_req.length = 0x0004;
				char *d = disc_req.serializuj();
			    if(send(my_socket,d,4,0)<0)
			    {
			        puts("Send failed");
			    }

			    delete [] d;
 

Jednakze nie wiem czy to eleganckie rozwiazanie// wydaje mi sie ze w tej funkcji otwieranej przez jest za duzo tresci i powinienem niektore rzeczy zmienic na metody co o tym myslicie? rozwazana funkcja:

void tcp_server::funkcja(int my_socket)
{
	char msg[512];
	fd_set rfds;
	struct timeval tv;
	int retval,maxfd;
	FD_ZERO(&rfds);
	FD_SET(my_socket,&rfds);
	tv.tv_sec=0;
	tv.tv_usec= 50000;
	maxfd=my_socket;
	cout<<"my_socket "<<my_socket<<endl;
	cout<<"maxfd "<<maxfd<<endl;
	int read_size,score;
//	----------------------------------
	 connect_req con_req;
	 connect_rsp con_rsp;
	 disconnect_req disc_req;
	 disconnect_rsp dis_con_rsp,dis_resp;
//	 ----------------------------------
	while(1)
	{
		if(info!=0)
		{
			while(1)
			    {
				disc_req.code = 0x0004;
				disc_req.length = 0x0004;
				char *d = disc_req.serializuj();
			    if(send(my_socket,d,4,0)<0)
			    {
			        puts("Send failed");
			    }

			    delete [] d;

			    bzero(msg,512);
			    recv(my_socket,msg,512,0);
			    dis_resp.deserializuj(msg);
				cout<<"Code: "<<dis_resp.code<<endl;
				cout<<"Lenhth: "<<dis_resp.length<<endl;
				cout<<"Status: "<<dis_resp.status<<endl;
				if(dis_resp.status=='a')
			     break;
			    }
		}
		puts("czelam na polaczenie");
		std::cout<<"nasluch na deskryptorze: "<<my_socket<<endl;
		retval = select(maxfd+1,&rfds,NULL,NULL,&tv);
		if(retval>=0)
     	{
			memset(msg,'\0',sizeof(msg));
	      	read_size = recv(my_socket,msg,512,0);
	      	if(read_size==0)
	      	{
	      		puts("client disconnected");
	      		fflush(stdout);
	      		close(my_socket);
	      		//~thread(); // destruktor watku
	      	}
	      	else if(read_size<0)
	      	{
	      		perror("recv failed*");
	      	}
	      	score = *((uint16_t *)&msg[ 0 ]);
	      	score = ntohs(score);
	      	switch(score)
	      	{
	        	case 1:
	      		{
	      		    con_req.deserializuj(msg);
	      			cout<<"Case0: "<<endl;
	      			cout<<"Code: "<<con_req.code<<endl;
	      			cout<<"Length: "<<con_req.length<<endl;
	      			cout<<"Message: "<<con_req.name;

	      			con_rsp.code = 0x0003;
	      			con_rsp.length = 0x0000;
	      			con_rsp.status = 144;
	      			char *q=con_rsp.serializuj();
	      			if(send(my_socket,q,sizeof(q),0)<0)
	      			{
	      			   puts("Send failed server_con_rsponse");
	      			   return;
	      			 }
	      		     delete [] q;
	      		   break;
	      		 }
	      		 case 3:
	      		 {
	      			break;
	      		 }
	      		 case 4:
	      		 {
	      		     disc_req.deserializuj(msg);
	      			 cout<<"Case4: "<<endl;
	      			 cout<<"Code: "<<disc_req.code<<endl;
	      			 cout<<"Lenhth: "<<disc_req.length<<endl;

	      			 dis_con_rsp.code = 0x0004;
	      			 dis_con_rsp.length = 0x0007;
	      			 dis_con_rsp.status = 97;
	      			 char* l=dis_con_rsp.serializuj();
	      			 if(send(my_socket,l,6,0)<0)
	      			 {
	      			     puts("Send failed");
	      			 }
	      			 cout<<"weszlo jak w maslo";
	      			 break;
	      		   }
	      		  case 5:
	      		  {
	      		      con_req.deserializuj(msg);
	      			  cout<<"Case5: "<<endl;
	      			  cout<<"Code: "<<con_req.code<<endl;
	      			  cout<<"Length: "<<con_req.length<<endl;
	      			  cout<<"Message: "<<con_req.name;

	      			  con_rsp.code = 0x0003;
	      			  con_rsp.length = 0x0000;
	      			  con_rsp.status = 144;
	      			  char *o=con_rsp.serializuj();
	      			  if(send(my_socket,o,sizeof(o),0)<0)
	      			  {
	      			      puts("Send failed server_con_rsponse");
	      				  return;
	      			  }
	      				delete [] o;
	      			  }
	      				break;
	      			default:
	      			{
	      				cout<<"brak dzialania";
	      			}
	      			break;
	      		}//switch

	      	}//retval>0
		else if(retval==0)
		{

			cout<<"retval 0"<<endl;
		}
		else
		{
			break;
			cout<<"mniejsze od 0"<<endl;
		}
		tv.tv_sec = 3;
		tv.tv_usec=50000;
		FD_ZERO(&rfds);
		FD_SET(my_socket,&rfds);
     	}//while

	close(my_socket);
	return;
}//tcp funkcja



			    bzero(msg,512);
			    recv(my_socket,msg,512,0);
			    dis_resp.deserializuj(msg);
				cout<<"Code: "<<dis_resp.code<<endl;
				cout<<"Lenhth: "<<dis_resp.length<<endl;
				cout<<"Status: "<<dis_resp.status<<endl;
				if(dis_resp.status=='a')
			     break;
			    }
		}

1 użytkowników online, w tym zalogowanych: 0, gości: 1