Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / С пониманием NamedPipes никто не поможет? Послать Message между приложениями. / 16 сообщений из 16, страница 1 из 1
13.01.2014, 17:46
    #38524810
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Задача

Приложение-сервер должно отправлять сообщение приложению-клиенту (скажем так без гарантии доставки меня устроит).

Я использовал:
1) сервер ищет hwndTarget окна клиента (FindWindow[Ex])
2) Если hwndTarget<>0 то SendMessage(hwndTarget, WM_COPYDATA)

Но к сожалению это не работает если сервер=SYSTEM (NT Service), а клиент=CURRENT_USER (кроме XP при условии что разрешено взаимодействие сервиса с рабочим столом).

MSDN рекомендует использовать NamedPipes.
Документации я почитал, типа
Named Pipe Server Using Overlapped I/O
Synchronous and Overlapped Pipe I/O

Коды разные попробовал, разные флаги для пайпа попробовал и т.д.

Дополнительное условие : и сервер и клиент - по единственному потоку , поэтому роскоши типа WaitForMultipleObjects или бесконечных Do Loop я в единственном потоке позволить себе не могу.

Т.е. что я хочу понять для себя перед тем как продолжу копание в документации.
Основной вопрос такой.
Пайп это вообще что? Буфер там есть?
Ну т.е. создал я пайп при старте сервера:
hPipe = CreateNamedPipe
У меня получается, что

1) Если сервер пишет в пайп
ConnectNamedPipe
WriteFile
FlushFileBuffers
DisconnectNamedPipe
то сервер висит пока клиент не прочтет посланную информацию

2) Если клиент читает из пайпа
CallNamedPipe (даже с NMPWAIT_NOWAIT)
то клиент висит пока сервер не пошлет ему чего-нибудь

Иными словами, висяки на сервере и клиенте...

А я хочу:
1) Сервер положил Message в пайп, забыл про него и занимается дальше своими делами
(без гарантии доставки клиенту)
2) Клиент по таймеру пришел в пайп, и если есть Message, то прочел его.
А если нет, то не ждет и занимается дальше своими делами.
3) Дополнительно хочу чтоб пайп очищался при старте клиента

И сдается мне что так не получится.

Или нужен механизм на клиенте, чтоб не по таймеру, а пайп стучал клиенту про новый message как только Message в пайпе появился.
Аналогичто тому как SendMessage стучится в WndProc клиентского окна. (как только так сразу без всяких там таймеров)

Есть какие соображения?
...
Рейтинг: 0 / 0
13.01.2014, 18:08
    #38524851
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Дмитрий77,

mailslot для связи без гарантии доставки и без установления соединения
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365794(v=vs.85).aspx
http://www.codeproject.com/Articles/8527/Using-Mailslots-for-Interprocess-Communication

Эту хрень времён царя Гороха лучше не пользовать, а использовать нормальный человеческий UDP
...
Рейтинг: 0 / 0
13.01.2014, 18:32
    #38524888
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
ИзопропилДмитрий77,

mailslot для связи без гарантии доставки и без установления соединения
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365794(v=vs.85).aspx
http://www.codeproject.com/Articles/8527/Using-Mailslots-for-Interprocess-Communication

Эту хрень времён царя Гороха лучше не пользовать, а использовать нормальный человеческий UDP

Присоединяюсь.

В общем-то NP -- это аналог стека TCP/UPD, но для другого протокола сетевого -- NetBIOS.
Когда-то микрософт собирался покорить мир без TCP/IP, но вовремя одумался...

Теперь в существовании этих протоколов нет смысла.
...
Рейтинг: 0 / 0
13.01.2014, 18:33
    #38524891
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
ИзопропилЭту хрень времён царя Гороха лучше не пользовать, ...Это ты про пайпы или про mailslot?

А про пайпы что можно сказать? В пайпы вроде как влез уже.
Вот влезу в mailslot, а там будут те же проблемы, не?

UDP я глядел, но что-то не охота.

Сервер по результатам работы посылает клиенту грубо текст,
а клиент отображает Tray Notification.
Клиент может быть не запущен.
Сервер тоже может быть остановлен (при наличии клиента=иконка трея).

Пока я сделал через таблицу в БД в качестве буфера и все работает. Но хочется конечно что нибудь поцивилизованнее. А м.б. и БД сойдет, пока не решил.
...
Рейтинг: 0 / 0
13.01.2014, 18:36
    #38524900
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Дмитрий77
А я хочу:
1) Сервер положил Message в пайп, забыл про него и занимается дальше своими делами
(без гарантии доставки клиенту)
2) Клиент по таймеру пришел в пайп, и если есть Message, то прочел его.
А если нет, то не ждет и занимается дальше своими делами.
3) Дополнительно хочу чтоб пайп очищался при старте клиента

И сдается мне что так не получится.

Или нужен механизм на клиенте, чтоб не по таймеру, а пайп стучал клиенту про новый message как только Message в пайпе появился.
Аналогичто тому как SendMessage стучится в WndProc клиентского окна. (как только так сразу без всяких там таймеров)




Это более похоже на mailSlots (от MS, параллельная спецификация к NamedPipes)
или на JMS-based message broker (типа ActiveMQ или Hornet).
Ты не думай, что если оно JMS, то это только для Java -- с C++ это тоже великолепно работает.
...
Рейтинг: 0 / 0
13.01.2014, 18:38
    #38524902
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Дмитрий77Это ты про пайпы или про mailslot?


Забыть можно и про то, и про другое.
...
Рейтинг: 0 / 0
13.01.2014, 18:44
    #38524906
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Дмитрий77Это ты про пайпы или про mailslot?
про оба. А внутри там всё равно TCP и UDP

Дмитрий77UDP я глядел, но что-то не охота.
в чём проблема?
...
Рейтинг: 0 / 0
13.01.2014, 18:47
    #38524910
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
MasterZivТы не думай, -- с C++ это тоже великолепно работает.
Ну, мне это надо сделать на VB6 (я деликатно промолчал, ибо какая разница).
Т.е. mailslot попробовать?
...
Рейтинг: 0 / 0
13.01.2014, 18:56
    #38524926
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Дмитрий77Ну, мне это надо сделать на VB6
там есть штатный winsock контрол http://msdn.microsoft.com/en-us/library/aa733709(v=vs.60).aspx

у него есть событие DataArrival http://msdn.microsoft.com/en-us/library/aa228046(v=vs.60).aspx
...
Рейтинг: 0 / 0
13.01.2014, 23:41
    #38525084
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Изопропилтам есть штатный winsock контрол
у него есть событие DataArrival
Да, я в курсе.
Даже пример как-то год назад мне давали:
Обмен сообщениями между двумя СВОИМИ приложениями

Смущает неколько вещей:
1)
Код: vbnet
1.
2.
3.
WinsockOutPut.Connect "127.0.0.1", 53424
WinsockInput2.LocalPort = "53427"
...

Порты задаюся явно. А вдруг "свободность" порта сглючит вместе со всей конструкцией.

2) Один уважаемый человек тут высказал опасение :
AntonariyМожно еще повиснуть винсоком на свободном tcp-порту, но для этого скорее всего потребуется разрешение брандмауэра .
3) Я не люблю добавлять в проекты дополнительные OCX-контролы даже от майкрософт.
И делаю это лишь в случае крайней необходимости.
...
Рейтинг: 0 / 0
14.01.2014, 02:20
    #38525129
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Дмитрий77,

да ты просто полон страхов...
...
Рейтинг: 0 / 0
14.01.2014, 08:17
    #38525188
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
NamedPipes редкостная хрень. Пытался разобраться, даже заработало, но с костылями: после ответа клиенту сервер переставал принимать сообщения, поэтому каждый раз закрытие пайпа и открытие заново.
Из за этого изврата со стороны клиента пришлось сделать несколько попыток открытия канала для отправки сообщения.
Сервер
Код: 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.
	HANDLE ghPipe = NULL;
	string gsPipe;
	gsPipe = "\\\\.\\pipe\\MyPipe";

	CHAR szBuf[1024];
	CHAR szAnswer[2048];

	DWORD dwRead, dwWaitCount;
	OVERLAPPED strOVERLAPPED;
	ZeroMemory(&strOVERLAPPED, sizeof(OVERLAPPED));
	strOVERLAPPED.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
	
	Console("Open pipe %s. Wait commands ...", gsPipe.c_str());
	while(1)
	{
		if(ghPipe == NULL) // Открытие канала
		{
			dwWaitCount = 0;
			ghPipe = CreateNamedPipe(gsPipe.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
							  PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
							  PIPE_UNLIMITED_INSTANCES, 32768, 32768,
							  NMPWAIT_USE_DEFAULT_WAIT, NULL 
							 );

			if(ConnectNamedPipe(ghPipe, &strOVERLAPPED) == 0 && GetLastError() != 997)
			{
				CloseHandle(ghPipe);
				ghPipe = NULL;
			}
		}
		else if(WaitForSingleObject(strOVERLAPPED.hEvent, 500) == WAIT_TIMEOUT) // Ожидание сообщения 0,5 сек
		{
			dwWaitCount++;
			if(dwWaitCount > 120) // Пересоздание канала раз в минуту на всякий случай
			{
				CloseHandle(ghPipe);
				ghPipe = NULL;
			}
		}
		else if(!ReadFile(ghPipe, szBuf, 1024, &dwRead, NULL)) // Чтение сообщения
		{
			CloseHandle(ghPipe);
			ghPipe = NULL;
		}
		else if(dwRead != 0)
		{
			szBuf[dwRead] = 0;
			// Ответ клиенту
			if(ParseCommand(szBuf, szAnswer)) // Разбор запроса и ответ в szAnswer
			{
				if(ghPipe != INVALID_HANDLE_VALUE)
				{
					DWORD dwWrite;
					WriteFile(ghPipe, szAnswer, strlen(szAnswer), &dwWrite, NULL); // отправка ответа
				}
			}
	
       			// Обязательно в конце закрыть канал
			CloseHandle(ghPipe);
			ghPipe = NULL;
		}
	}

	// Завершение работы
	CloseHandle(strOVERLAPPED.hEvent);


Клиент у меня на фоксе, но думаю понятно, т.к. использованы только функции WinAPI
Клиент
Код: 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.
* Обращение к PIPE-серверу
func CallPipe
lpara tcPipe, tcWrite, tnWait
* Запрос в PIPE канал tcPipe. Отправляет tcWrite и ожидает ответа
* Через tnWait секунд останавливается. По умолчанию 1 сек.
* возвращает ответ сервера или пусто при ошибках.
local lcRet, i, lnHPipe, lcBuf, lnRead
if !'\' $ tcPipe
	tcPipe = '\\.\pipe\' + tcPipe
endif
if vartype(tnWait) != 'N'
	tnWait = 1
endif
if type('glDeclarePipeAPI') = 'U'
	public glDeclarePipeAPI
	DECLARE INTEGER CreateFile IN WIN32API STRING, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER
	DECLARE INTEGER ReadFile IN WIN32API INTEGER, STRING @, INTEGER, INTEGER @, INTEGER
	DECLARE INTEGER WriteFile IN kernel32 INTEGER, STRING, INTEGER, INTEGER @, INTEGER
	DECLARE INTEGER CloseHandle IN WIN32API INTEGER
	DECLARE INTEGER Sleep IN WIN32API INTEGER
	DECLARE INTEGER PeekNamedPipe IN WIN32API INTEGER, STRING @, INTEGER, INTEGER @, INTEGER, INTEGER
endif
lcRet = ''
* Соединение
for i = 1 to 10
	lnHPipe = CreateFile(tcPipe, BITOR(0x40000000, 0x80000000), 0, 0, 3, 0, 0)
	if lnHPipe > 0
		exit
	endif
	Sleep(100)
endfor

if lnHPipe > 0
	* Отправка
	lnRead = 0
	lcBuf = space(1024)
	if WriteFile(lnHPipe, tcWrite, len(tcWrite), @lnRead, 0) > 0
		* Ожидание ответа
		for i = 1 to tnWait * 100
			do case
				case PeekNamedPipe(lnHPipe, @lcBuf, 1024, @lnRead, 0, 0) = 0
					* ошибка канала
					exit
				case lnRead = 0
					* нет ответа
				
				case ReadFile(lnHPipe, @lcBuf, 1024, @lnRead, 0) > 0
					* ответ прочитан
					lcRet = left(lcBuf, lnRead)
					exit
			endcase
			Sleep(10)
		endfor
	endif
	CloseHandle(lnHPipe)
endif

return lcRet


Работает стабильно, правда нагрузка небольшая.
У меня сервер зацикленный ждет запроса и тутже шлет ответ, но используется асинхронный режим, думаю можно допилить под твои нужды. Только отправить второе сообщение не получится пока первое не принято.

AntonariyМожно еще повиснуть винсоком на свободном tcp-порту, но для этого скорее всего потребуется разрешение брандмауэра .
Если слушать 127.0.0.1 то брандмауэр не заблокирует.

PS Есть библиотека ZMQ , по сути надстройка над TCP для обмена сообщениями. Бесплатная, кроссплатформенная. Для целей "передал и забыл" подходит идеально. Сама занимается установкой и поддержанием соединения, гарантирует доставку отправленного целиком, а не частями. Еще много чего интересного в документации, изучаю, но я еще только базовые моменты освоил.
...
Рейтинг: 0 / 0
14.01.2014, 10:06
    #38525247
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Dima TNamedPipes редкостная хрень. Пытался разобраться, даже заработало, но с костылями

протокол не виноват
...
Рейтинг: 0 / 0
14.01.2014, 10:46
    #38525286
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Изопропилпротокол не виноват
Не буду спорить, примеры его использования от MS ниасилил. Свои задачи я порешал, а остальное неважно.
...
Рейтинг: 0 / 0
14.01.2014, 11:17
    #38525322
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Дмитрий77Есть какие соображения?
Обычный COM применить. (межпроцессное взаимодействие будет спрятано в его потрохах)
Дмитрий77Порты задаюся явно. А вдруг "свободность" порта сглючит вместе со всей конструкцией.
динамически выбрать
Дмитрий77Я не люблю добавлять в проекты дополнительные OCX-контролы даже от майкрософт.
строй велосипед с квадратными колёсами
...
Рейтинг: 0 / 0
15.01.2014, 01:21
    #38526397
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Изопропил,MasterZiv

Отличный совет:
Изопропил mailslot для связи без гарантии доставки и без установления соединения
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365794(v=vs.85).aspx
http://www.codeproject.com/Articles/8527/Using-Mailslots-for-Interprocess-Communication... MasterZivЭто более похоже на mailSlots (от MS, параллельная спецификация к NamedPipes).
БОЛЬШОЕ ВАМ СПАСИБО
И кстати в документации нигде не сказано, что технология устаревшая.
===
Документация простенькая и понятная. В точности отвечает поставленной задаче.
Уже все сделал.
Проверил на XP и на Win 2012 R2 и из под "As Service" тоже. Отлично все работает.
Я на всякий случай приложил тест-проект, хотя это и VB6.

СЕРВЕР-ПРИЕМНИК:
Код: vbnet
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.
Private Sub Form_Load()
  MakeMailSlot("\\.\mailslot\MailSlots")
End Sub

Private Sub CommandReadAll_Click()
  Dim the_Message As String
  Dim the_MsgCount As Long
  Do
    If MailSlotReadFirst(the_Message, the_MsgCount) Then
      '---обработка сообщения---
      MsgBox the_Message
      '---обработка сообщения---
      If the_MsgCount = 0 Then Exit Do
    Else
      Exit Do
    End If
  Loop
End Sub

Private Sub Form_Unload(Cancel As Integer)
  CloseMailSlot 'правда смысла нет, он ПО-ЛЮБОМУ уничтожится ВМЕСТЕ С ПРОЦЕССОМ
End Sub

'==========
Public hMailSlotHandle As Long

Public Function MakeMailSlot(ByVal lpszSlotName As String) As Boolean
  'ПРИЕМНИК(сервер) ф-ция создает MailSlot с именем lpszSlotName
  'невозможно создать более одного MailSlot с заданным именем
  Dim m_tSA As SECURITY_ATTRIBUTES

  If LenB(lpszSlotName) = 0 Then
    ' No slotname
    hMailSlotHandle = INVALID_HANDLE_VALUE
    MakeMailSlot = False
    Exit Function
  End If
 
  ' The handle to the slot
  hMailSlotHandle = CreateMailslot(lpszSlotName, 0, 0, m_tSA)
  
  MakeMailSlot = (hMailSlotHandle > 0)
End Function

Public Sub CloseMailSlot()
  'ПРИЕМНИК(сервер) ф-ция уничтожает MailSlot
  'При этом все непрочитанные сообщения также уничтожаются
  'При закрытии приложения (включая принудительное типа End Task/kill) MailSlot и сообщения также уничтожатся
  If hMailSlotHandle > 0 Then
    CloseHandle hMailSlotHandle
    hMailSlotHandle = INVALID_HANDLE_VALUE
  End If
End Sub

Public Function AvailableMessages() As Long
  'ПРИЕМНИК(сервер) ф-ция возвращает общее к-во сообщений, доступных для чтения
  If hMailSlotHandle = INVALID_HANDLE_VALUE Then Exit Function
  GetMailslotInfo hMailSlotHandle, 0, 0, AvailableMessages, 0
End Function

Public Function MailSlotReadFirst(ByRef m_Message As String, ByRef m_MsgCount As Long) As Boolean
  'ПРИЕМНИК(сервер) ф-ция читает первое сообщение если есть
  'возвращает True, если есть хотя бы одно и оно было прочитано
  'm_Message (Out)-текст сообщения, если прочли
  'm_MsgCount -к-во сообщений оставшихся после чтения (без учета прочитанного)
  Dim lBufferSize As Long
  m_Message = ""
  m_MsgCount = 0
  GetMailslotInfo hMailSlotHandle, 0, lBufferSize, m_MsgCount, 0
  If m_MsgCount > 0 Then
    Dim sBuffer As String, lBytesRead As Long
    ' Create a buffer
    sBuffer = String(lBufferSize, 0)
    
    ' Read data: optional параметры ф-ции не используем
    If ReadFile(hMailSlotHandle, sBuffer, lBufferSize) Then
      m_Message = sBuffer
      m_MsgCount = m_MsgCount - 1
      MailSlotReadFirst = True
    End If
  End If
End Function

КЛИЕНТ - ПЕРЕДАТЧИК:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
Private Sub CommandSend_Click()
  SendMessageToMailSlot Text1.Text, "\\.\mailslot\MailSlots"
End Sub
'====

Public Function SendMessageToMailSlot(ByVal sMessage As String, ByVal sMailSlot As String) As Boolean
  'ПЕРЕДАТЧИК(клиент)ф-ция отправляет сообщение sMessage серверу с именем sMailSlot
  'если сервер не запущен, то сообщение не отправляется
  Dim hFile As Long
  Dim m_tSA As SECURITY_ATTRIBUTES
  
  hFile = CreateFile(sMailSlot, _
                     GENERIC_WRITE, _
                     FILE_SHARE_READ, _
                     m_tSA, _
                     OPEN_EXISTING, _
                     FILE_ATTRIBUTE_NORMAL)
  If hFile = INVALID_HANDLE_VALUE Then Exit Function
  
  SendMessageToMailSlot = WriteFile(hFile, sMessage, Len(sMessage))
  CloseHandle hFile
End Function

...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / С пониманием NamedPipes никто не поможет? Послать Message между приложениями. / 16 сообщений из 16, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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