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

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

Собственно что не устраивает в текущем режиме работы: при недоступности сервера (ребут например) соединение не разрывается. То есть данные просто перестают поступать из сокета. Надо чтобы это отслеживалось и сокет создавался заново.
...
Рейтинг: 0 / 0
09.12.2004, 17:58
    #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
09.12.2004, 19:01
    #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
10.12.2004, 01:13
    #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
10.12.2004, 01:20
    #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
10.12.2004, 10:42
    #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
10.12.2004, 11:06
    #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
14.12.2004, 11:20
    #32826222
notarius
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты
Кстати! проблема так и не исчезла:
notariusСобственно что не устраивает в текущем режиме работы: при недоступности сервера (ребут например) соединение не разрывается. То есть данные просто перестают поступать из сокета. Надо чтобы это отслеживалось и сокет создавался заново.
...
Рейтинг: 0 / 0
14.12.2004, 17:03
    #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
14.12.2004, 17:50
    #32827336
Roman S. Golubin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты
Да, совсем забыл. Самое главное. В GetConnectedSocket установи опцию сокета ReceiveTimeout в ненулевое значение.

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

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

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


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