Форум программистов
 
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

Вернуться   Форум программистов > C++ > C/C++ Сетевое программирование
Регистрация

Восстановить пароль
Повторная активизация e-mail


Донат для форума - использовать для поднятия настроения себе и модераторам

А ещё здесь можно купить рекламу за 25 тыс руб в месяц! ) пишите сюда - alarforum@yandex.ru

Ответ
 
Опции темы
Старый 11.09.2017, 12:21   #1
Андрей Цапко
Форумчанин
 
Регистрация: 10.04.2017
Сообщений: 66
Репутация: 10
По умолчанию Выбирается случайный порт при перезапуске

Здравствуйте. Я пишу скромный сервер. Есть 2 проблемы. При запуске, точнее при перезапуске, выбирается случайный порт. В коде четко задан 80 порт, но при перезапуске сервера он выбирает рандомный. Что бы он запустился на 80 нужно немного подождать. Из за чего это может быть?
И второй вопрос. Как правильно распаралелить выполнение?
Код сервера:
Код:
//Стандартные библиотеки
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>

#include <iostream>

using namespace std;

class Server{
public:
	int sock;
	struct sockaddr_in config;

	Server(){
		//Конфигурация
		config.sin_family=AF_INET;
		config.sin_port=htons(80);
		config.sin_addr.s_addr=inet_addr("10.0.2.15");

		//Инициалзиация
		sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		bind(sock, (struct sockaddr *)&config, sizeof(config));
		listen(sock, 128);
	}
	~Server(){
		shutdown(sock, 2);
		close(sock);
	}
	
} server;
Код самой прогаммы:
Код:
//Стандартные библиотеки
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <thread>

//Классы
#include </etc/local/c++/server.class.cpp> //Класс сервера и инициализация объекта
#include </etc/local/c++/client.class.cpp> //Класс клиента и инициализация объекта
#include </etc/local/c++/default.cpp> //Класс сервера и инициализация объекта

using namespace std;

int main(){
	thread potok;
	while(sock=accept(server.sock, (struct sockaddr *)&config, size)){
		potok=thread(handler, ref(sock), ref(config), i);
		potok.detach();
	}
	delete size;
	return 0;
}
в функции хэндлер происходит обработка запроса. Не уверен что все выполняется независимо. И компилятор жалуется на этот код. Что бы все скомпилировалось приходится добавлять -pthread в консоли. ОС ubuntu server 17.04 компилятор g++;
Андрей Цапко вне форума   Ответить с цитированием
Старый 11.09.2017, 12:47   #2
Pavia
Лис
Профессионал
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 1,939
Репутация: 2059
По умолчанию

Андрей Цапко
Цитата:
Сообщение от Андрей Цапко Посмотреть сообщение
При запуске, точнее при перезапуске, выбирается случайный порт. В коде четко задан 80 порт, но при перезапуске сервера он выбирает рандомный. Что бы он запустился на 80 нужно немного подождать. Из за чего это может быть?
Это нормальное поведение. Насколько помню случайный порт создаётся при создании сокета socket.
Помниться я смотрел код апача что-бы выяснить как уменьшить паузу для смены.


Цитата:
Сообщение от Андрей Цапко Посмотреть сообщение
Не уверен что все выполняется независимо. И компилятор жалуется на этот код. Что бы все скомпилировалось приходится добавлять -pthread в консоли. ОС ubuntu server 17.04 компилятор g++;
Ничего плохого в добавление ключа нету.
Вот только имеет смысл использовать бустовские потоки, как самые проработанные.
__________________
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума   Ответить с цитированием
Старый 11.09.2017, 12:53   #3
Pavia
Лис
Профессионал
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 1,939
Репутация: 2059
По умолчанию

Цитата:
Сообщение от Андрей Цапко Посмотреть сообщение
Не уверен что все выполняется независимо.
Учтите, что время создания одного потока может быть до нескольких сотен мс. Когда потоки скопятся в пуле они уже будут быстро создаваться. Вернее просто будут выбираться из пула, что снизит время создания до мкс.
__________________
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума   Ответить с цитированием
Старый 11.09.2017, 12:59   #4
Cuprum5
Участник клуба
 
Регистрация: 09.05.2017
Сообщений: 523
Репутация: 104
По умолчанию

Цитата:
Сообщение от Андрей Цапко Посмотреть сообщение
Код:
while(sock=accept(server.sock, (struct sockaddr *)&config, size))
- а тут равно или присваивание?
Cuprum5 вне форума   Ответить с цитированием
Старый 11.09.2017, 13:12   #5
Pavia
Лис
Профессионал
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 1,939
Репутация: 2059
По умолчанию

Cuprum5
Присвоение, мы одобряем входящее соединение и одновременно создаём входящий сокет. Так что тут верно, что должно быть присвоение.
А если есть ошибка, то вместо сокета будет признак-ошибки, а он отрицательный.
accept(2)
Но такой стиль ведёт к ошибкам, так что лучше разделить сравнение и присвоение.
__________________
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума   Ответить с цитированием
Старый 11.09.2017, 17:38   #6
Андрей Цапко
Форумчанин
 
Регистрация: 10.04.2017
Сообщений: 66
Репутация: 10
По умолчанию

выбирался случайный порт который прослушивался. Это было из за того что на соединение от старого сервера было не до конца закрыто. Я немного подправил пограмму, но у меня теперь при попытке загрузить 2 страницы одновременно вызвается сегментирование памяти. Есть подозрение что я не правильно работаю с потоками, но документации которая мне помогла бы я найти не смог.

Код:
//Стандартные библиотеки
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <thread>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>


//Классы
// #include </etc/local/c++/server.class.cpp> //Класс сервера и инициализация объекта

class Server{
public:
	int sock;

	Server(){
		//Конфигурация
		config.sin_family=AF_INET;
		config.sin_port=htons(80);
		config.sin_addr.s_addr=inet_addr("10.0.2.15");

		//Инициалзиация
		sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		int value=1;
		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
		bind(sock, (struct sockaddr *)&config, sizeof(config));
		listen(sock, 128);
	}
	~Server(){
		shutdown(sock, 2);
		close(sock);
	}

private:
	struct sockaddr_in config;

} server;

// #include </etc/local/c++/client.class.cpp> //Класс клиента
class Client{
public:
	char *ip;

	Client(int &sock, sockaddr_in &config){
		//Инициализация конфигурации
		this->sock=sock;
		ip=inet_ntoa(config.sin_addr);
		read();
	}

	~Client(){
		delete request;
		send(sock, response.c_str(), response.size(), 0);
		shutdown(sock, 2);
		close(sock);
	}

	void read(){
		recv(sock, request, 1024, 0);

		const unsigned short int len=strlen(request)-2;
		unsigned short int count=0;
		char *part;
		int i;

		for(i=0; i<len; i++){
			if(request[i]=='\r'){
				count++;
				i++;
			}
		}

		headers=new string[count];
		part=strtok(request, "\r\n");

		for(i=0; i<count; i++){
			headers[i]=part;
			part=strtok(NULL, "\r\n");
			// cout<<headers[i]<<endl;
		}
		// cout<<endl<<endl;

	}

	void header_parse(){
		//
	}

	void operator<<(char information[]){
		response+=information;
	}

	void operator<<(const char information[]){
		response+=information;
	}

private:
	int sock;

	//Данные из сокета
	char *request=new char[1024];
	string *headers;

	string response="HTTP/1.1 200 OK\r\n"
		"Date: Wed, 09 Aug 2017 19:33:44 GMT\r\n"
		"Server: LocalServer/1.0 (Ubuntu)\r\n"
		"CVary: Accept-Encoding\r\n"
		"Connection: Keep-aleave\r\n"
		"Content-Type: text/html; charset=UTF-8\r\n"
		"\r\n"
		"<!DOCTYPE html>"
		"<html lang=\"ru\">"
		"<head>"
		// "<meta http-equiv=\"refresh\" content=\"5; url=/\">"
		"<title>C++</title>"
		"</head>"
		"<body>"
		"<h1>Hello World!</h1>"
		"<h2>This is C++!</h2>"
		"<h3>На русском</h3>"
		"</body>"
		"</html>";
};

// #include </etc/local/c++/default.cpp> //Основные функции и переменные

void handler(int &sock, sockaddr_in &config){
	Client client(sock, config);
}

//Переменные
int sock; //Временный сокет клиента
struct sockaddr_in config; //Временная структура клиента
socklen_t *size=new socklen_t(sizeof(config)); //Временный размер структуры клиента

using namespace std;

int main(){
	thread potok;
	while(sock=accept(server.sock, (struct sockaddr *)&config, size)){
		potok=thread(handler, ref(sock), ref(config));
		potok.detach();
	}
	delete size;
	return 0;
}
классы импортируются из других файлов (выше класса закомментировано подключение этого файла), функция handler и три переменных из третьего класса. Подскажите что не так с потоками и почему сегментирование памяти.
Андрей Цапко вне форума   Ответить с цитированием
Старый 11.09.2017, 17:47   #7
Андрей Цапко
Форумчанин
 
Регистрация: 10.04.2017
Сообщений: 66
Репутация: 10
По умолчанию

Ещё я не могу понять, почему по домену, привязанному к ip адресу по которому я захожу, я зайти не могу. Браузер просто опускает запрос и он вроде бы не доходит до сервера.
P.S. Разобрался. У меня был запущен опенсервер который менял ip адрес домена.

Последний раз редактировалось Андрей Цапко; 11.09.2017 в 18:07.
Андрей Цапко вне форума   Ответить с цитированием
Старый 11.09.2017, 18:59   #8
Pavia
Лис
Профессионал
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 1,939
Репутация: 2059
По умолчанию

1) неправельно работаешь с открытыми массивами параметров.
В handler неправельно описан.
Подтянутся проС++ расскажут как правильно.
А пока советую уменьшить до 1 - параметра.

См https://stackoverflow.com/questions/...threading-in-c
2) у браузера тайм-аут на accept 2.5 секунды. Так что пока ты моргал и задумывался какую кнопку жать - браузер успел разорвать соединение. Поэтому отучиваемся от отладчика переходим на логированиее и модульное тестирование.
__________________
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума   Ответить с цитированием
Старый 11.09.2017, 19:16   #9
Андрей Цапко
Форумчанин
 
Регистрация: 10.04.2017
Сообщений: 66
Репутация: 10
По умолчанию

Я убрал ссылки на переменные и передаю просто переменные в handler. Ошибка с сегментацией осталась но появляется не раз в 10 запросов а раз в 1000 запросов, но мне все равно кажется, что запросы будут обрабатываться по очереди. Немного не понял про " у браузера тайм-аут на accept 2.5 секунды". Что вы имеете ввиду? То что браузер спустя 2.5 секунды обрывает соединение если сервер его не принял? В общем задача такая, что бы сервер обрабатывал 2 вида запросов (GET и POST) и передавал его в другую программу через сокет ( как прокси nginx). При этом сервер должен сделать это быстрее чем nginx (обработки запроса по большому счету меньше). Запрос будет перенаправлен на 1 из двух серверов в зависимости от метода и сервер должен передать только путь и какие то из параметров (допустим host, user-agent и accept-lagneage)
Андрей Цапко вне форума   Ответить с цитированием
Ответ

Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
DBCheckBox не выбирается Scorpuha БД в Delphi 4 14.01.2014 11:19
При подключении на открытый порт Connect возвращает -1 Nullerset C/C++ Сетевое программирование 2 28.12.2013 15:33
Случайный Access Violation при добавлении новой записи alm4 Общие вопросы Delphi 3 16.07.2012 10:23
Проблема при передаче через Com-порт ShlakBaum Assembler 0 01.02.2010 22:59
В каждой строке массива выбирается максимальный элемент sergeyfsd Общие вопросы Delphi 2 13.05.2008 00:10


22:25.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.