Socketfehler 10053 bei mehren Clients

SBX

Grünschnabel
Guten Tag,
ich schreibe zur Zeit einen FTP-Server. Das funktioniert soweit auch. Jedoch tritt immer ein Fehler auf, wenn zwei Clients verbunden sind.
So sieht das Szenario aus:
Client1 verbindet sich / listet
Client2 verbindet sich / listet
Client1 versucht eine Datenverbindung einzuläuten (sendet RETR / STOR / APPE / LIST)
Client2 wird getrennt ( recv() gibt -1 zurück und WSAGetLastError() 10053 )
Client1 wartet vergebens auf die Datenverbindung

Ich bin absolut verzweifelt, da ich mir diesen Fehler nicht erklären kann.
Ich hab u.a. auch den Server auf anderen Rechnern getestet, aber das ist alles witzlos. :(

OS: Windows XP SP2
Entwicklungsumgebung: Visual Studio 2007 / Orcas

Ich bedanke mich schon mal herzlichst im voraus.
 
Zuletzt bearbeitet:
Hallo,

also ich hab vor kurzem auch einen FTP-Server geschrieben, die Grundfunktionen funktionieren auch schon wunderbar. Zu deinem Problem: Vielleicht wäre es hilfreich, wenn du ein wenig Code zeigen würdest? Du machst das ganze doch sicherlich mit select(), oder?

Gruß
cesupa
 
Danke erstmal für deine Antwort. Ich habe bislang noch nicht die select() Funktion verwendet.

Der Code zum Annehmen eines Clients
Code:
CArray<CClient*,CClient*&> aClients;

BOOL CFtpServer::StartListening()
{
	CSocketEx::InitWinsock();
	if(!AcceptSocket.Create())
		return FALSE;
	if(!AcceptSocket.Bind(m_nPort))
		return FALSE;
	pThis = this;
	AcceptSocket.Listen(10);
	while(aClients.GetCount() < 64)
	{
		CClient* pClient = new CClient();
		if(AcceptSocket.Accept(&pClient->ConSocket))
		{
			pClient->hThread = CreateThread(0,0,CreateClient,(LPVOID)pClient,0,&pClient->dwThreadID);
			aClients.Add(pClient);
		}
		else
			delete pClient;
	}
	return TRUE;
} 

DWORD WINAPI CFtpServer::CreateClient(LPVOID p)
{
	CSocketEx::InitWinsock();
	CClient* pClient = (CClient*)p;
	pClient->Interact(); // die Funktion in der der FTP-Server die komplette Kommunikation mit dem Client durchführt
	pClient->ConSocket.Close();
	for(int i=0;i<pThis->aClients.GetCount();i++)
	{
		if(pThis->aClients.ElementAt(i) == pClient)
		{
			pThis->aClients.RemoveAt(i);
			return 0;
		}
	}
	return 0;
}

Code zum Einläuten und Annehmen einer passiven Verbindung
Code:
BOOL CFtpServer::CClient::OnPASVCommand(CString szIn)
{
	UINT uiPort, nPasvPort[2];
	nPasvPort[0] = rand()%m_pDomain->m_nRangeLength+m_pDomain->m_nDataPort[0]; //Zufallsport aus dem Portbereich wählen
	//nPasvPort[0] = m_pFtp->GetPort();
	nPasvPort[1] = nPasvPort[0]%256;
	nPasvPort[0]-=nPasvPort[1];
	nPasvPort[0]/=256;
	if(!AcceptSocket.Create())
	{
		return FALSE;
	}
	if(!AcceptSocket.Bind(nPasvPort[0]*256+nPasvPort[1]))
	{
		return FALSE;
	}
	if(!AcceptSocket.Listen(1))
	{
		return FALSE;
	}
	ConSocket.GetSockName(szIn,uiPort);
	szIn.Replace(".",",");
	szIn.AppendFormat(",%d,%d",nPasvPort[0],nPasvPort[1]);
	szIn.Insert(0,"227 Entering passive mode (");
	szIn.Append(")\r\n");
	m_dwDataConType = DATACONTYPE_PASV;
	Send(szIn);
	return TRUE;
}

DWORD WINAPI CFtpServer::CClient::InitDataConnectionPasv(LPVOID p)
{
	if(!pThis->AcceptSocket.Accept(&pThis->DataSocket))
	{
		pThis->AcceptSocket.Close();
		return -1;
	}
	pThis->AcceptSocket.Close();
	return 0;
}

Ich hoffe, dass das an Code reicht. Das schien mir für den Fehler relevant.
 
Ich habe es nun mit select() versucht jedoch ohne jeden Erfolg. Es verläuft genauso wie zuvor.

Code:
BOOL CFtpServer::StartListening()
{
	CSocketEx::InitWinsock();
	if(!AcceptSocket.Create())
		return FALSE;
	if(!AcceptSocket.Bind(m_nPort))
		return FALSE;
	pThis = this;
	AcceptSocket.Listen(10);
	CClient* pHelpClient;
	int nRet;
	char* pszBuf = (char*)malloc(2048);
	while(1)
	{
		FD_ZERO(&fdSet);
		FD_SET(AcceptSocket.Socket,&fdSet);
		for(int i=0;i<aClients.GetCount();i++)
		{
			pHelpClient = aClients.ElementAt(i);
			if(pHelpClient->ConSocket.Socket != INVALID_SOCKET)
			{
				FD_SET(pHelpClient->ConSocket.Socket,&fdSet);
			}
		}
		nRet = select(0,&fdSet,NULL,NULL,NULL);
		if(nRet == SOCKET_ERROR)
			return FALSE;
		if(FD_ISSET(AcceptSocket.Socket,&fdSet))
		{
			CClient* pClient = new CClient();
			if(AcceptSocket.Accept(&pClient->ConSocket))
			{
				FD_SET(pClient->ConSocket.Socket,&fdSet);
				pClient->hThread = CreateThread(0,0,CreateClient,(LPVOID)pClient,0,&pClient->dwThreadID);
				aClients.Add(pClient);
			}
			else
				delete pClient;
		}
		for(int i=0;i<aClients.GetCount();i++)
		{
			pHelpClient = aClients.ElementAt(i);
			if(pHelpClient->ConSocket.Socket == INVALID_SOCKET)
				continue;
			if(FD_ISSET(pHelpClient->ConSocket.Socket,&fdSet))
			{
				ZeroMemory(pszBuf,2048);
				pHelpClient->ConSocket.Receive(pszBuf,2048);
				memcpy(pHelpClient->pszCmd,pszBuf,2048); // pszCmd ist der Puffer für die Befehle
			}
		}
	}
	return TRUE;
}
 
Also so auf den ersten Blick fallen mir zwei Dinge auf, wobei ich mich mit dem VC++ gar nicht auskenne.

1. Du brauchst für jeden Client einen freien(!) Socket. Das heißt also wenn sich zwei clients anmelden brauchst du auch zwei freie Sockets. Wo setzt du fest, wieviele Sockets vom Programm erstellt werden sollen?

2. Wie schon gesagt muss ein verwendeter Socket wieder "frei" gegeben werden wenn die Verbindung getrennt wird. Heißt also du musst diesen Socket wieder auf "INVALID_SOCKET" setzen.

Gruß
cesupa
 
Ich habe mir eine Klasse CSocketEx erstellt, in der die Standardfunktion für Sockets eingebunden sind. Die Klasse CDomain::CClient besitzt 3 Instanzen dieser Klasse:
ConSocket für die Steuerungsverbindung, DataSocket für den Datentransfer und AcceptSocket zum Akzeptieren von passiven Verbindungen.

Mit
Code:
CClient* pClient = new CClient();
wird eine neue Instanz erzeugt. Somit ist die maximale Anzahl der Clients theoretisch unbegrenzt.

Das Problem scheint bei den Datenverbindungen zu liegen. Ich habe nun weiter getestet. Wenn keine Datenverbindungen eingeläutet / aufgebaut werden, dann funktioniert das alles (was da so alles ist).
Und da jeder Client seinen eigenen AcceptSocket und DataSocket hat, verstehe ich das Problem nicht.
Ich hab das auch schon mit einem gemeinsamen AcceptSocket probiert, wobei das Ergebnis dem vorherigen ähnlich ist.
 
Ich habe das Problem gelöst. Das Problem waren nicht die Sockets, sondern dass ein Pointer (pThis) auf eine falsche Speicherstelle zeigte.
Nochmals vielen Dank für deine Mühen.
 
Zurück