powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сокеты
11 сообщений из 11, страница 1 из 1
Сокеты
    #32821618
notarius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день!
Есть некоторый сервис (Windows Service), построенный по след. принципу:
в методе OnStart устанавливается bool переменная is_work в true
далее по событию Elapsed таймера вызывается функция, которая открывает сокет и пока is_work = true читает из сокета данные (в синхронном режиме) и складываются в БД.
При остановке сервиса is_work устанавливается в false и соответственно чтение прекращается, соединения закрываются.

Вопрос: подходит ли такая организация работы для подобной задачи? или принято делать как-то иначе?
выгоднее ли (по любому параметру) использовать асинхронные сокеты?
если выгоднее, то как реализовать в данном контексте асинхронное чтение?

Собственно что не устраивает в текущем режиме работы: при недоступности сервера (ребут например) соединение не разрывается. То есть данные просто перестают поступать из сокета. Надо чтобы это отслеживалось и сокет создавался заново.
...
Рейтинг: 0 / 0
Сокеты
    #32821686
Фотография Roman S. Golubin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Лучше создавать отдельный thread и читать данные в нем асинхронно:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
class Service {

private Thread _workThread = null;

public Service(){
  _workThread = new Thread(new ThreadStart(Work));
}

OnStart(){
  _workThread.Start();
}

OnStop(){ 
  _workThread.Abort();
}

private void Work(){
  Socket s = new Socket(....);
  ...
  while(true){
    try
    {
      IAsyncResult ar = s.BeginRead(...., null, null);
      ar.AsyncWaitHandle.WaitOne();
      int length = s.EndRead(...);
    }
    catch(ThreadAbortException)
    {
       break;
    }
  }

}

}

--
WBR, Roman S. Golubin
...
Рейтинг: 0 / 0
Сокеты
    #32821849
Фотография Лиман Артём
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
у меня вопрос:
для чего сдесь асинхронность:?
Код: plaintext
1.
2.
IAsyncResult ar = s.BeginRead(...., null, null);
ar.AsyncWaitHandle.WaitOne();
или я чего не понимаю, но мне кажеться, что это все равно что вызвать синхронно, ведь ar.AsyncWaitHandle.WaitOne(); будет ждать завершения BeginRead, или не так?
и еще, может так будет лучше?
Код: plaintext
1.
2.
3.
4.
public Service(){
  _workThread = new Thread(new ThreadStart(Work));
 _workThread.IsBackground = true;
}
...
Рейтинг: 0 / 0
Сокеты
    #32822099
Фотография Roman S. Golubin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Лиман Артёму меня вопрос:
для чего сдесь асинхронность:?
Код: plaintext
1.
2.
IAsyncResult ar = s.BeginRead(...., null, null);
ar.AsyncWaitHandle.WaitOne();
или я чего не понимаю, но мне кажется, что это все равно что вызвать синхронно, ведь ar.AsyncWaitHandle.WaitOne(); будет ждать завершения BeginRead, или не так?

Данный кусок кода был приведен как пример ухода от переменной bool is_work. Странно, что Read вместо Receive тебя не смутило :-)
Лиман Артём
и еще, может так будет лучше?
Код: plaintext
1.
2.
3.
4.
public Service(){
  _workThread = new Thread(new ThreadStart(Work));
  _workThread.IsBackground = true;
}

Ну да. Извините. Люди над душой стояли - домой звали... :-\
...
Рейтинг: 0 / 0
Сокеты
    #32822100
Фотография Roman S. Golubin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну и раз уж начали исправлять то что написано выше, то добавлю еще:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
OnStart(){
  _workThread.Start();
  Thread.CurrentThread.Sleep(0);
}

OnStop(){ 
  _workThread.Abort();
  _workThread.Join();
}
...
Рейтинг: 0 / 0
Сокеты
    #32822471
Фотография Roman S. Golubin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Лиман Артёму меня вопрос:
для чего сдесь асинхронность:?
Код: plaintext
1.
2.
IAsyncResult ar = s.BeginRead(...., null, null);
ar.AsyncWaitHandle.WaitOne();
или я чего не понимаю, но мне кажеться, что это все равно что вызвать синхронно, ведь ar.AsyncWaitHandle.WaitOne(); будет ждать завершения BeginRead, или не так?


Блин. Я аж сам задумался - почему-то все время так пишу :-)
При использовании Receive есть проблема с завершением thread при использовании просто Receive. Проблема такого плана, что пока соединение не разорвано принудительно удаленным хостом и при этом удаленный хост не отправляет ни каких данных, thread не может завершиться (даже Thread.IsBackground = true не поможет :-)) и продолжает выполнять Receive. В приведенном же мной примере при Thread.Abort thread сразу же вываливается с исключением ThreadAbortException.

PS: Даже не знаю - баг это или фича такая ;-))
...
Рейтинг: 0 / 0
Сокеты
    #32822546
notarius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Roman S. GolubinНу и раз уж начали исправлять то что написано выше, то добавлю еще:
Код: plaintext
1.
  Thread.CurrentThread.Sleep(0);

Спасибо всем за помощь! Только вот на строчку выше компилятор ругался:
Static member 'System.Threading.Thread.Sleep(int)' cannot be accessed with an instance reference; qualify it with a type name instead

Когда изменил на Thread.Sleep(0); - замолчал
...
Рейтинг: 0 / 0
Сокеты
    #32826222
notarius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Кстати! проблема так и не исчезла:
notariusСобственно что не устраивает в текущем режиме работы: при недоступности сервера (ребут например) соединение не разрывается. То есть данные просто перестают поступать из сокета. Надо чтобы это отслеживалось и сокет создавался заново.
...
Рейтинг: 0 / 0
Сокеты
    #32827221
Фотография Roman S. Golubin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Смотри пример - специально для тебя написал :-)

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
public class MyService : System.ServiceProcess.ServiceBase
{

		// Признак запущенного сервиса
		private bool _isAlive = false;
		// Собственно сокет, представляющий устанавливаемое соединение
		private Socket _socket = null;
		// Параметры подключения сокета
		private IPEndPoint _remoteEP = null;
		// Семафор, блокирующий основной thread до момента завершения инициализации и остановки дочернего thread
		private ManualResetEvent _workStarted = null;
		private ManualResetEvent _workStopped = null;

/// ...

		protected override void OnStart(string[] args)
		{
			// Если сервис уже выполняется, возвращаем управление.
			if(_isAlive) return;
			// Разбираем входные параметры (GetDestinationEndPoint возвращает 
			// адрес и порт с которым необходимо устанавливать соединение
      _remoteEP = this.GetDestinationEndPoint(args);
			// Создаем новый thread
			Thread thread = new Thread(new ThreadStart(DoService));
			// Создаем семафор, указывающий на окончание инициализации нового thread
			// и на его завершение работы
			_workStarted = new ManualResetEvent(false);
			_workStopped = new ManualResetEvent(false);
			// Запускаем новый thread
			thread.Start();
			// Ожидаем сигнала семафора
			_workStarted.WaitOne();
		}
 
		protected override void OnStop()
		{
			// Удостоверяемся в том, что сервис был запущен ранее
			if(!_isAlive) return;
			// Устанавливаем указатель на необходимость завершения сервиса
			_isAlive = false;
			// Закрываем слушающий сокет
			_socket.Shutdown(SocketShutdown.Both);
			_socket.Close();
			_socket = null;
			_workStopped.WaitOne();
		}

		private void DoService()
		{

			Thread.CurrentThread.IsBackground = true;
			Thread.CurrentThread.Name = "my service thread";

			// Устанавливаем указатель выполнения потока сервиса
			_isAlive = true;
			// Устанавливаем семафор окончания инициализации thread
			_workStarted.Set();
			// Инициализируем буфер в который будем читать
			byte[] buffer = new byte[1024];
			// Устанавливаем локальные переменные
			int length = 0;
			// Пока сервис не остановлен
			while(_isAlive)
			{
				try
				{

					// Функция GetConnectedSocket() возвращает новый подключенный сокет...
					_socket = this.GetConnectedSocket();

					while(true)
					{
						// Читаем данные из сокета
						length = _socket.Receive(buffer);
						// В случае закрытия соединения создаем исключение сокета
						if(!(length > 0)) throw new SocketException();

						// TODO: Добавить свой обработчик полученных данных

					}
				}
				catch(SocketException e)
				{
					switch(e.ErrorCode)
					{

							// TODO: Здесь обрабатываем интересующие нас ошибки сокета...
							// Например:

						case 10051: //WSAENETUNREACH

							// Если сеть назначения не доступна, вываливаемся с остановкой сервиса
							// и записью в лог

							// TODO: Обработчик ошибки "сеть назначения не доступна"

							break;

						/// Полный список возможных ошибок читай в MSDN (Winsock Error Codes)

						default:
							// При необрабатываемой нами ошибке сокета (например, соединение 
							// было разорвано) пытаемся продолжить выполнение работы и создать 
							// соединение заново. 
							continue;
					}
				}
					/// В случае возникновения ошибки не связанной с работой соединения
					/// выполняем завершение работы цикла
				catch(Exception)
				{
					break;
				}
			}
			// Устанавливаем семафор окончания работы сервиса
			_workStopped.Set();
		}

		private IPEndPoint GetDestinationEndPoint(string[] args)
		{
			// TODO: Здесь разбираем входные параметры сервиса

			// Допустим, мы хотим подключаться к локальному серверу http:
			return new IPEndPoint(IPAddress.Any, 80);
		}

		private Socket GetConnectedSocket()
		{
			// TODO: Здесь создаем соединение

			// Например:
      Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			socket.Connect(_remoteEP);

			return socket;
		}
}
...
Рейтинг: 0 / 0
Сокеты
    #32827336
Фотография Roman S. Golubin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, совсем забыл. Самое главное. В GetConnectedSocket установи опцию сокета ReceiveTimeout в ненулевое значение.

socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout, XXXX);

XXXX - время ожидания данных от сервера, после которого должно произойти исключение SocketException, которое попытается установить новое соединение.

PS: Да. И еще - прежде чем создавать новое соединение надо бы старое прибивать.
...
Рейтинг: 0 / 0
Сокеты
    #32827528
notarius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ну просто мегаспасибо.
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сокеты
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]