不允许发送或接收数据的请求,因为套接字未连接且未提供地址

时间:2017-02-04 12:27:14

标签: c# wpf sockets

我已经在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。 欢迎任何帮助。

1 个答案:

答案 0 :(得分:0)

我发现了我的错误。在LoginServerSide函数中首次发送&#34; OK&#34;我使用listen socked( _socket )而不是在accept( socket )上创建的工作套接字。