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

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

Я использовал:
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
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
    #38524851
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий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
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
    #38524888
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилДмитрий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
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
    #38524891
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилЭту хрень времён царя Гороха лучше не пользовать, ...Это ты про пайпы или про mailslot?

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

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

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

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

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

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




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


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

Дмитрий77UDP я глядел, но что-то не охота.
в чём проблема?
...
Рейтинг: 0 / 0
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
    #38524910
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivТы не думай, -- с C++ это тоже великолепно работает.
Ну, мне это надо сделать на VB6 (я деликатно промолчал, ибо какая разница).
Т.е. mailslot попробовать?
...
Рейтинг: 0 / 0
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
    #38524926
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий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
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
    #38525084
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропилтам есть штатный winsock контрол
у него есть событие DataArrival
Да, я в курсе.
Даже пример как-то год назад мне давали:
Обмен сообщениями между двумя СВОИМИ приложениями

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

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

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

да ты просто полон страхов...
...
Рейтинг: 0 / 0
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
    #38525188
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
    #38525247
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TNamedPipes редкостная хрень. Пытался разобраться, даже заработало, но с костылями

протокол не виноват
...
Рейтинг: 0 / 0
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
    #38525286
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропилпротокол не виноват
Не буду спорить, примеры его использования от MS ниасилил. Свои задачи я порешал, а остальное неважно.
...
Рейтинг: 0 / 0
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
    #38525322
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Есть какие соображения?
Обычный COM применить. (межпроцессное взаимодействие будет спрятано в его потрохах)
Дмитрий77Порты задаюся явно. А вдруг "свободность" порта сглючит вместе со всей конструкцией.
динамически выбрать
Дмитрий77Я не люблю добавлять в проекты дополнительные OCX-контролы даже от майкрософт.
строй велосипед с квадратными колёсами
...
Рейтинг: 0 / 0
С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
    #38526397
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропил,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
16 сообщений из 16, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / С пониманием NamedPipes никто не поможет? Послать Message между приложениями.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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