TarasCo:
TC>Это в общем случае UB, надо closesocket делать
Простите, но что есть "UB" и где взять функцию closesocket? В каталоге <include/*.h> её нету, и компилятор её не знает.
--------------------------------------------------------
andreytsb:
A>В идеальных условиях (на локальной машине) даже при одновременном подключении нескольких клиентов (с помощью telnet) сервер обработал всех поочередно: как только отсоединялся текущий — обрабатывалось следующее соединение).
A>Проблема очень интересная. Чтобы полностью разобратся нужно лицезреть полный код клиента и сервера.
Вот код сервера, собран с помощью GNU GCC под Debian Etch4:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
int main()
{
int sock, listener;
struct sockaddr_in addr;
char buf[1024];
int bytes_read;
listener = socket(AF_INET, SOCK_STREAM, 0);
if (listener < 0)
{
return 1;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(3425);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
return 2;
}
while (1)
{
listen(listener, 1);
while(1)
{
sock = accept(listener, NULL, NULL);
if (sock < 0)
{
return 3;
}
while(1)
{
bytes_read = recv(sock, buf, 1024, 0);
if (bytes_read <= 0) break;
send(sock, buf, bytes_read, 0);
std::cout << buf << std::endl;
}
close(sock);
}
}
return 0;
}
Клиент, который собственно не работает. Собран под MSVC6.0 + MFC в виде простейшего диалога с кнопкой. Код выполняется по нажатию на эту кнопку. Первое нажатие отрабатывает как положено, сервер всё принимает/отсылает/печатает, второе и последующие нажатия — никакой реакции сервера. В отладчике видно, что pUM_Socket->Connect() возвращает 0.
void CUmEmulatorDlg::OnButtonConnect()
{
if (pUM_Socket) // переменная объявлена как CSocket* CUmEmulatorDlg::pUM_Socket;
{
AfxMessageBox("Already connected!");
return;
}
pUM_Socket = new CSocket();
CString Str;
Str = "192.168.0.22";
int nPort = 3425;
pUM_Socket->Create(nPort, SOCK_STREAM, NULL);
pUM_Socket->Connect(Str, nPort);
Str = "SESSION BEGIN AB5643F8865CD0\n";
pUM_Socket->Send(Str.GetBuffer(Str.GetLength()), Str.GetLength(), 0);
pUM_Socket->Receive(Str.GetBuffer(Str.GetLength()), Str.GetLength(), 0);
Str = "GET STATE AB5643F8865CD0\n";
pUM_Socket->Send(Str.GetBuffer(Str.GetLength()), Str.GetLength(), 0);
pUM_Socket->Receive(Str.GetBuffer(Str.GetLength()), Str.GetLength(), 0);
pUM_Socket->Close();
delete pUM_Socket;
pUM_Socket = NULL;
}
Для проверки написал простенький аналог этого клиента под Debian, но запустить его, к сожалению, могу лишь локально с сервером, а по реальной сети запускать его не на чем. Этот клиент работает корректно, сколько бы раз его ни запускали, при том, что он сам по себе делает пяток независимых соединений:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
char message[] = "Hello there!\n";
char buf[sizeof(message)];
int main()
{
int sock;
struct sockaddr_in addr;
for (int i=0; i<5; i++)
{ sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
return 1;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(3425);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
return 2;
}
send(sock, message, sizeof(message), 0);
recv(sock, buf, sizeof(message), 0);
std::cout << buf << std::endl;
close(sock);
}
return 0;
}
======================================================
Пока писал этот текст, провёл несложный эксперимент:
Запустил сервер. Подключился удалённым клиентом несколько раз. Как и раньше, получилось лишь единожды. После этого, не выключая сервер, запустил локальный клиент и сервер корректно обработал его запросы.
Очевидно, что либо клиент под MFC работает некорректно, либо сервер как-то иначе обрабатывает именно loopback-соединения (вообще-то он и знать об этом не должен, но мало ли...).
Может у кого-нибудь есть мысли, где тут собака порылась?..