Мы пишем клиенту и серверу, чтобы сделать (что я думал, был), довольно простая сетевая связь. Клиенты Mulitple соединяются с сервером, который тогда, как предполагается, передает данные обратно всем другим клиентам.
Сервер просто находится в блокировании select
цикл, ожидающий трафика, и когда это прибывает, отправляет данные другим клиентам. Это, кажется, работает просто великолепно.
Проблемой является клиент. В ответ на чтение это будет иногда хотеть сделать запись.
Однако я нашел это, если я использую:
rv = select(fdmax + 1, &master_list, NULL, NULL, NULL);
Мой код заблокируется, пока не будут новые данные для чтения. Но иногда (асинхронно, от другого потока) у меня будут новые данные для записи на потоке сетевой связи. Так, я хочу, чтобы мой выбор периодически просыпался и позволял мне проверить, существуют ли данные для записи, как:
if (select(....) != -1)
{
if (FD_SET(sockfd, &master_list))
// handle data or disconnect
else
// look for data to write and write() / send() those.
}
Я пытался установить выбор для опроса режима (или смехотворно короткие тайм-ауты) с:
// master list contains the sockfd from the getaddrinfo/socket/connect seq
struct timeval t;
memset(&t, 0, sizeof t);
rv = select(fdmax + 1, &master_list, NULL, NULL, &t);
но нашли, что тогда тогда клиент никогда не получает входящих данных.
Я также пытался установить сокет fd, чтобы не заблокироваться, как:
fcntl(sockfd, F_SETFL, O_NONBLOCK);
но это не решает проблему:
select()
имеет нет struct timeval
, чтение работ данных, но это никогда не разблокирует, чтобы позволить мне искать перезаписываемые данные.select()
имеет a timeval
чтобы заставить это опрашивать, затем это никогда не сигнализирует, что там поступают данные для чтения, и мои замораживания приложения, думающие, что нет никакого сделанного сетевого соединения (несмотря на то, что все другие вызовы функции успешно выполнились),Какие-либо указатели вообще относительно того, что я мог делать неправильно? Разве не возможно сделать чтение-запись на том же сокете (я не могу полагать что быть верным).
(РЕДАКТИРОВАНИЕ: корректный ответ и вещь, которую я помнил на сервере, но не на клиенте, должны иметь второй fd_set и скопировать master_list перед каждым вызовом для выбора ():
// declare and FD_ZERO read_fds:
// put sockfd in master_list
while (1)
{
read_fds = master_list;
select(...);
if (FD_ISSET(read_fds))
....
else
// sleep or otherwise don't hog cpu resources
}
)
Все выглядит хорошо, кроме линии, где вы делаете , если (fd_set (sockfd, & master_list))
. У меня очень похожая структура кода и использовала FD_isset
. Вы должны проверить, установлен ли список, чтобы не установить его снова. Кроме того, я ничего не вижу.
Редактировать. Кроме того, у меня есть следующее для тайм-аута:
timeval listening_timeout;
listening_timeout.tv_sec = timeout_in_seconds;
listening_timeout.tv_usec = 0;
Возможно, есть проблема, если вы установите его на 0 (как вы, кажется, делаете?)
edit2. Я вспомнил, что я столкнулся с странной проблемой, когда я не очищал набор читателей после выбора, и прежде чем я снова ввел его. Я должен был сделать что-то вроде:
FD_ZERO(&sockfd);
FD_SET(sockfd, &rd);
, прежде чем я входил , выберите
. Я не могу вспомнить, почему, хотя.
Я написал модуль PowerShell под названием VisioPS , который может вам помочь (См. раздел загрузки здесь: * Модуль VisioPS является частью моей библиотеки VisioAutomation на CodePlex )
После установки VisioPS вы запускаете экземпляр PowerShell и делаете следующее:
Import-Module VisioPS
New-VisioApplication
New-VisioDocument
$dg = Import-VisioDirectedGraph c:\foo.xml
Invoke-VisioDraw $dg
Direct Graph - это простой XML-документ, подобный этому
<directedgraph>
<page>
<renderoptions
usedynamicconnectors="true"
scalingfactor="20"
/>
<shapes>
<shape id="n1" label="FOO1" stencil="server_u.vss" master="Server" url="http://microsoft.com" />
<shape id="n2" label="FOO2" stencil="server_u.vss" master="Email Server" url="http://contoso.com"/>
<shape id="n3" label="FOO3" stencil="server_u.vss" master="Proxy Server" url="\\isotope\public" />
<shape id="n4" label="FOO4" stencil="server_u.vss" master="Web Server">
<customprop name="prop1" value="value1"/>
<customprop name="prop2" value="value2"/>
</shape>
<shape id="n5" label="FOO4" stencil="server_u.vss" master="Application Server" />
</shapes>
<connectors>
<connector id="c1" from="n1" to="n2" label="LABEL1" />
<connector id="c2" from="n2" to="n3" label="LABEL2" color="#ff0000" weight="2" />
<connector id="c3" from="n3" to="n4" label="LABEL1" color="#44ff00" />
<connector id="c4" from="n4" to="n5" label="" color="#0000ff" weight="5"/>
<connector id="c5" from="n4" to="n1" label="" />
<connector id="c6" from="n4" to="n3" label="" weight="10"/>
</connectors>
</page>
</directedgraph>
Я, кажется, вспоминаю хитрость в создании и совместном использовании дескриптора файлов для чтения/записи между сетевым потоком и основным потоком, который добавляется к дескрипторам в вызове select. Этот fd имеет один байт, записанный в него главным потоком, когда ему есть что отправить. Запись пробуждает сетевой поток из вызова выбора, и сетевой поток затем захватывает данные из общего буфера и записывает их в сеть, затем возвращается в спящий режим в выбранном.
Извините, если это немного расплывчато и не хватает кода... и моя память может быть неправильной.. так что другим, возможно, придется направлять вас дальше.
-121--2948983- Я не вижу ничего плохого в вашем коде, поэтому он должен работать. Если он не может работать, один из способов обойти его - создать трубу, которая будет использоваться читающей нитью и нитью, которая готовит вещи для записи, и добавить конец для чтения трубы в набор select
. Затем, когда другой поток подготовил данные для записи, он просто посылает что-то на канал, ваш поток чтения просыпается из select
, и он может затем сделать запись. В зависимости от того, как часто имеются данные для чтения или записи, это также может быть более эффективным.
Я, кажется, вспомним трюк о создании и совместном использовании Filedescriptor чтения / записи между сетевым потоком и основным потоком, который добавляется к дескрипторам в выборе. Эта FD имеет один байт, написанный ему главным потоком, когда оно есть что отправлять. Запись Wack UP Network Thread из вызова SELECT и сетевая резьба снимает данные из общего буфера и записывает его в сеть, а затем вернитесь, чтобы спать в выборе.
Извините, если это немного расплывчато и не хватает кода ... и моя память может быть неверной .. То, что другие могут придеться вам дальше.
2 потока должны иметь возможность работать с одним и тем же сокетом одновременно, поэтому ваш основной поток должен иметь возможность писать клиенту, пока другой спит в выберите ожидание входящих данных. Это, конечно, предполагает, что оба потока имеют доступ к списку клиентов.