Framework winsock/sockets problem z portem na linuxa.

0

Witam! Ostatnio w wolnych chwilach kodziłem frameworka na winsock, a teraz przyszło mi do głowy żeby przerobić go tak , aby działał też na linuxie. Fajnie, trochę poczytałem i wyszło - program się kompiluje, niestety nie działa tak jak powinien. Nie wiem jak jest na linuxie, w każdym razie mój framework przyjmuje klienta bez wywołania accept()... Niżej kluczowy kod:

http://4programmers.net/Pastebin/1730

Select z ListenThread() nigdy nie zwraca 1(bez znaczenia czy podam pierwszy parametr 0 czy 1) mimo to klient się łączy... i łączy się do mojego servera, bo kiedy go wyłączę jest błąd połączenia. Ostatnio nawet zrobiłem tak, że zakomentowałem tworzenie wątku z metody StartServer, a klient ciągle się łączy... Czytalem sporo na necie o select, accept pod linuxem, ale już nie mam pojęcia co może być źle... Prosze o pomoc, z góry dzięki.

0
if(select( 1, &Read, NULL, NULL, &Timeout)==1 )

Jeśli dobrze pamiętam, pod windowsem pierwszy parametr funkcji select jest ignorowany, pod unixami ma on znaczenie i powinien być poprawnie ustawiony. Czyli, jeśli dobrze czytam Twój kod, jakoś tak to powinno wyglądać:

if(select(*m_ConnectionManager + 1, &Read, NULL, NULL, &Timeout)==1 ) { ... } 
#ifdef WIN32
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CServer::StartListenThread, reinterpret_cast<void*>(this), 0, NULL);
#else
...
pthread_attr_setdetachstate(&ThreadCfg, PTHREAD_CREATE_DETACHED);
...
pthread_create(...);
#endif

Drobny szczegół, pod windowsem wątki nie są typu detached, uchwyt powinien zostać usunięty funkcją CloseHandle.

0

Wielkie dzięki, poprawka pierwszego parametru do select pomogła(teraz mam nowy problem, ale chyba dam radę)! Wątki też poprawie, jeszcze raz dzięki ;)

0

No to jeszcze jeden szczegół odnośnie wątków w windowsie - tak mi się przypomniało. Jeśli korzystasz z runtime'ów visualowych w wersji multithreaded, do tworzenia wątków powinieneś użyć funkcji _beginthreadex. W przeciwnym wypadku możesz mieć drobne wycieki pamięci.

0

Znowu pojawiły się niejasności, kod:

 

template<typename PacketsHeaderType, bool AutoRecvPacketsHeaders>
bool CClient<PacketsHeaderType, AutoRecvPacketsHeaders>::RecvData()
{
		fd_set Read;
		FD_ZERO(&Read);
		FD_SET(*m_ConnectionManager, &Read);

		timeval Timeout;
		Timeout.tv_sec = 0;
		Timeout.tv_usec = 10;

		if( select(*m_ConnectionManager+1, &Read, NULL, NULL, &Timeout) )
		{

			int Received=recv(*m_ConnectionManager, *m_Packet, m_Packet->GetSizeOfFreeSpace(), 0);
			if( Received<1 )
			{
				#ifdef DEBUG
				CLogger* logger=CLogger::GetClassRef();
				logger->LogError("CClient::Tick - recv. kod bledu: %d", WSAGetLastError());
				#endif

				return false;

			}else
				m_Packet->IncreaseDataCountInBuffer(Received);

		}

	return true;
}

To kod z klasy klienta, pod windowsem jeżeli wyłączę server wykrywany jest błąd i zwracana wartość false. Pod linuxem nie ma takiej opcji, select w ogóle nie reaguje na zerwanie połączenia ze strony servera. Dziwne... no ale poszukałem na necie informacji i znalazłem.

http://www.linuxquestions.org/questions/programming-9/how-could-server-detect-closed-client-socket-using-tcp-and-c-824615/#post4061212

Kod który podał użytkownik dwhitney67 w gruncie rzeczy nie różni się od mojego(tak mi się wydaje), a jest zaznaczony jako zaakceptowana odpowiedź. Może ktoś mi powiedzieć o co tu chodzi? Znowu jakiś parametr źle podaje?

0

Dziwna sprawa. select powinien wykryć zamknięcie socketa niezależnie od platformy na jakiej był wywołany. W kodzie błędów nie widzę... Sprawdzałeś co zwraca select?

0

Zrobiem plik w ktorym zapiswywalem wartosci zwracane przez select:

http://4programmers.net/Pastebin/1734

Same 0 i 1, wiec chyba wszystko ok.

Return Value

On success, select() and pselect() return the number of file descriptors contained in the three returned descriptor sets (that is, the total number of bits that are set in readfds, writefds, exceptfds) which may be zero if the timeout expires before anything interesting happens. On error, -1 is returned, and errno is set appropriately; the sets and timeout become undefined, so do not rely on their contents after an error.

Ma ktos jeszcze jakis pomysl?

0

Heh, mogłeś darować sobie wklejanie 5471 zer i jedynek ;)

Spróbuj może z funkcją ioctl:

unsigned long bytes2read;

int res = ioctl(*m_ConnectionManager, FIONREAD, &bytes2read); 

Może będzie jakaś sensowniejsza reakcja na zamknięty socket.

0

Ciągle to samo, ioctl zwraca zera czyli teoretycznie nie wystąpił błąd... Dziwne ;/.

1 użytkowników online, w tym zalogowanych: 0, gości: 1