我已经在Stackoverflow上阅读了有关此问题的所有帖子,但没有解决我的问题。 我已经为我正在构建的使用TCP套接字的客户端 - 服务器应用程序创建了身份验证类:
public class Authentication
{
private Socket _socket;
private AddressFamily _addressFamily;
private SocketType _socketType;
private ProtocolType _protocolType;
private IPAddress _ipAddress;
private IPEndPoint _ipEndPoint;
private bool _running = true;
public Authentication(SocketType socketType, AddressFamily family, ProtocolType protocolType)
{
_addressFamily = family;
_socketType = socketType;
_protocolType = protocolType;
}
public int Connect(string ipAdd, int port)
{
try
{
_addressFamily = AddressFamily.InterNetwork;
_ipAddress = IPAddress.Parse(ipAdd);
_ipEndPoint = new IPEndPoint(_ipAddress, port);
_socket = new Socket(_addressFamily, _socketType, _protocolType);
_socket.Connect(_ipEndPoint);
return 0;
}
catch (Exception e)
{
return -1;
}
}
public int Listen(string ipAdd, int port, ClientManager clientManager)
{
try
{
_ipAddress = IPAddress.Parse(ipAdd);
_ipEndPoint = new IPEndPoint(_ipAddress, port);
_socket = new Socket(_addressFamily, _socketType, _protocolType);
_socket.Bind(_ipEndPoint);
while (_running)
{
_socket.Listen(30000);
Socket socket = _socket.Accept();
Thread thread = new Thread(() =>
{
ConnectionAccepted(ref socket, clientManager);
});
thread.Start();
}
return 0;
}
catch (Exception e)
{
return -1;
}
}
private void ConnectionAccepted(ref Socket socket, ClientManager clientManager)
{
try
{
string command = "";
do
{
byte[] len = new byte[4];
socket.Receive(len); //receive length of command
byte[] buffer = new byte[BitConverter.ToInt32(len, 0)];
socket.Receive(buffer);
command = Encoding.Unicode.GetString(buffer);
if (command.Contains("LOGIN"))
LoginServerSide(ref socket, clientManager);
else if (command.Contains("REGISTER"))
RegisterServerSide(socket, clientManager);
} while (!command.Contains("TERMINATE"));
Close(socket);
}
catch (Exception ex)
{
}
}
public bool LoginClientSide(string username, string password)
{
if (_socket == null)
return false;
//send action
byte[] login = Encoding.Unicode.GetBytes("LOGIN");
_socket.Send(BitConverter.GetBytes(login.Length));
_socket.Send(login);
byte[] ok = new byte[4];
_socket.Receive(ok);
if (Encoding.Unicode.GetString(ok) == "OK")
{
//send username
byte[] usernameBytes = Encoding.Unicode.GetBytes(username);
_socket.Send(usernameBytes);
ok = new byte[40];
_socket.Receive(ok); //OK: salt_value
if (Encoding.Unicode.GetString(ok).Split(':').First() == "OK")
{
//get salt
byte[] saltBytes = Encoding.Unicode.GetBytes(Encoding.Unicode.GetString(ok).Split(':').Last());
//send hashed password
byte[] passwordBytes = Encoding.Unicode.GetBytes(password);
byte[] hashedPassword = CreateHashedPassword(passwordBytes, saltBytes);
_socket.Send(hashedPassword);
_socket.Receive(ok);
if (Encoding.Unicode.GetString(ok) == "OK")
return true;
}
}
return false;
}
private void LoginServerSide(ref Socket socket, ClientManager clientManager)
{
byte[] ok = Encoding.Unicode.GetBytes("OK");
byte[] err = Encoding.Unicode.GetBytes("ER");
//response to action
_socket.Send(ok);
//receive username
byte[] buffer = new byte[50];
socket.Receive(buffer);
string username = Encoding.Unicode.GetString(buffer);
//check for existing user
if (clientManager.CheckForUser(username))
{
//user exists send OK: salt_value
byte[] salt = clientManager.GetSalt(username);
socket.Send(Encoding.Unicode.GetBytes("OK: " + salt));
//receive hashed password
buffer = new byte[64];
socket.Receive(buffer);
byte[] hashedPassword = clientManager.GetHashedPassword(username);
if (buffer.SequenceEqual(hashedPassword))
{
//password is ok
socket.Send(ok);
}
socket.Send(err);
}
//user does not exist
socket.Send(err);
}
public KeyValuePair<byte[], long> RegisterClientSide(string username, string password)
{
if (_socket == null)
throw new Exception("Socket not initialized");
byte[] register = Encoding.Unicode.GetBytes("REGISTER");
_socket.Send(BitConverter.GetBytes(register.Length));
_socket.Send(register);
byte[] ok = new byte[4];
_socket.Receive(ok);
string tmp = Encoding.Unicode.GetString(ok);
if (tmp == "OK")
{
//send username
byte[] usernameBytes = Encoding.Unicode.GetBytes(username);
_socket.Send(usernameBytes);
ok = new byte[4];
_socket.Receive(ok);
if (Encoding.Unicode.GetString(ok) == "OK")
{
//generate and send salt
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] salt = new byte[16];
rng.GetNonZeroBytes(salt);
_socket.Send(salt);
_socket.Receive(ok);
if (Encoding.Unicode.GetString(ok) == "OK")
{
//send hashed password
byte[] passwordBytes = CreateHashedPassword(Encoding.Unicode.GetBytes(password), salt);
_socket.Send(passwordBytes);
_socket.Receive(ok);
if (Encoding.Unicode.GetString(ok).Split(':').First() == "OK")
{
byte[] idBytes = new byte[8];
_socket.Receive(idBytes);
long id = BitConverter.ToInt64(idBytes, 0);
//created new user
return new KeyValuePair<byte[], long>(salt, id);
}
//server error
}
//server error
}
//username exists
}
return new KeyValuePair<byte[], long>();
}
private void RegisterServerSide(Socket socket, ClientManager clientManager)
{
byte[] ok = Encoding.Unicode.GetBytes("OK");
byte[] err = Encoding.Unicode.GetBytes("ER");
//response to action
socket.Send(ok);
//receive username
byte[] buffer = new byte[50];
socket.Receive(buffer);
string username = Encoding.Unicode.GetString(buffer).TrimEnd('\0');
//check for existing user
if (!clientManager.CheckForUser(username))
{
//user does not exist send ok
socket.Send(ok);
//receive salt
buffer = new byte[16];
socket.Receive(buffer);
//save salt
byte[] salt = new byte[16];
buffer.CopyTo(salt, 0);
//send ok
socket.Send(ok);
//receive hashed password
buffer = new byte[64];
socket.Receive(buffer);
//save hashed password
byte[] pass = new byte[64];
buffer.CopyTo(pass, 0);
//send ok: id
long id = clientManager.CreateNewUser(username, pass, salt);
socket.Send(Encoding.Unicode.GetBytes("OK"));
socket.Send(BitConverter.GetBytes(id));
}
else
socket.Send(err);
}
}
现在在WPF应用程序中我使用这个类进行注册,它工作得很好但是当登录时它会在服务器尝试发送“OK”时中断,并且我在本文的标题中给出了错误。 这是在客户端进行注册的方式:
Authentication _auth = new Authentication(SocketType.Stream, AddressFamily.InterNetwork, ProtocolType.Tcp);
_auth.Connect(_serverIPAdd, _port);
KeyValuePair<byte[], long> info = _auth.RegisterClientSide(reg.Username.Text, reg.Password.Text);
和登录:
Authentication _auth = new Authentication(SocketType.Stream, AddressFamily.InterNetwork, ProtocolType.Tcp);
_auth.Connect(_serverIPAdd, _port);
bool login = _auth.LoginClientSide(login.textBox.Text, login.textBox1.Text)
在服务器端:
Authentication _auth = new Authentication(SocketType.Stream, AddressFamily.InterNetwork, ProtocolType.Tcp);
_auth.Listen(_IPAddress, _port, this);
因此,您可以看到我执行了将客户端连接到服务器的相同过程,但在一种情况下,这会传递,而在其他情况下(登录)则会失败。 IP地址是我的本地IP,端口是30012。 欢迎任何帮助。
答案 0 :(得分:0)
我发现了我的错误。在LoginServerSide函数中首次发送&#34; OK&#34;我使用listen socked( _socket )而不是在accept( socket )上创建的工作套接字。