C#TCP聊天服务器:连接仅适用于一种方式

时间:2014-04-30 14:01:55

标签: c# tcp connection

我的主笔记本电脑和另一台笔记本电脑上安装了通用TCP客户端和TCP侦听器。客户端和听众是他们自己的单独的程序,所以我在两台笔记本电脑上都运行了一个客户端和服务器,试图让简单的即时通讯工具。< / p>

  1. 如果两个程序都在同一台笔记本电脑上执行,客户端和服务器将愉快地进行沟通。这对我的主笔记本电脑和其他笔记本电脑都是如此。

  2. 我的主要笔记本电脑的客户端很乐意将消息发送到我的其他笔记本电脑其他笔记本电脑将优雅地接收来自我的主要笔记本电脑。

  3. 但是,当我的其他笔记本电脑的客户端向我的主笔记本电脑的服务器发送消息时,它会收到超时相关的通信失败类型错误。它只是没有发送消息。

  4. 错误消息(由try-catch捕获); &#34;连接尝试失败,因为连接方在一段时间后没有正确响应,或者由于已连接的主机已建立连接失败未能回复{我的IP:端口号}。&#34;

    我正确地获取了IP和端口号,因此请将其排除在外。 没有防火墙业务,因为另一台笔记本电脑根本不关心从我的主笔记本电脑接收消息。

    我还尝试了随机端口号并确保我的主笔记本电脑上的客户端通过我的其他笔记本电脑的服务器正在侦听的端口号连接(或接受来自的消息。

    那么为什么我的另一台笔记本电脑没有成功地向我的主笔记本电脑发送消息呢?

    客户端要求用户输入IP,然后输入端口号。然后它等待用户输入消息,然后连接并通过给定的端口号将该消息发送到IP。

    服务器要求用户输入端口号并打印通过该端口接收的消息。

    这是客户端程序的代码;

    static void Main(string[] args)
        {
            string IP = localIPAddress();
            Console.WriteLine("Your IP: " + IP); //provides IP number
            Console.Write("Enter IP to connect to: ");
            string connectToIP = Console.ReadLine();
            if (connectToIP == "self")
            {
                connectToIP = localIPAddress(); 
                // if I want to test both on the same computer
            }
            Console.WriteLine("\nEnter port number: ");
            int portNo = int.Parse(Console.ReadLine());
    
            while (true)
            {
                string message = Console.ReadLine();
                try
                {
                    // connection doesn't begin until ReadLine is done
                    request(connectToIP, portNo, message); 
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
    
        public static string localIPAddress()
        {
            IPHostEntry host;
            string localIP = "?";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIP = ip.ToString();
                }
            }
            return localIP;
        }
    
        static void request(string address, int port, string message)
        {
            TcpClient client = new TcpClient();
    
            client.SendTimeout = 1000;
            client.ReceiveTimeout = 1000;
    
            try
            {
                client.Connect(address, port);
                StreamWriter sw = new StreamWriter(client.GetStream());
    
                sw.WriteLine(message);
    
                sw.Flush();
    
                sw.Close();
            }
            catch (Exception a)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(a.Message.ToString());
                Console.ResetColor();
            }
        }
    

    这是服务器的代码;

    static void Main(string[] args)
        {
            Console.WriteLine("Your IP: " + localIPAddress());
            Console.Write("Enter port number you're receiving from: ");
            int portNo = int.Parse(Console.ReadLine());
    
            TcpListener listener = new TcpListener(IPAddress.Any, portNo);
            Socket connection;
            NetworkStream socketStream;
            listener.Start();
            while (true)
            {
                connection = listener.AcceptSocket();
                connection.SendTimeout = 1000;
                connection.ReceiveTimeout = 1000;
                socketStream = new NetworkStream(connection);
                try
                {
                    respond(socketStream);
                }
                catch(Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                finally
                {
                    socketStream.Close();
                    connection.Close();
                }
            }
        }
    
        public static string localIPAddress()
        {
            IPHostEntry host;
            string localIP = "?";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIP = ip.ToString();
                }
            }
            return localIP;
        }
    
        static void respond(NetworkStream strm)
        {
            List<string> sentIn = new List<string>();
            StreamReader sr = new StreamReader(strm);
    
            while (sr.Peek() != -1)
                sentIn.Add(sr.ReadLine());
    
            sr.Close();
    
            foreach (string s in sentIn)
            {
                Console.WriteLine(s);
            }
        }
    

    我的代码有问题吗?当笔记本电脑使用这些程序时,没有与防火墙相关的消息。

    它可能是客户端的sw.Flush(),因为它曾导致发送进程冻结。

    提前致谢。一旦我对此问题进行了排序,我就会开始想知道如何使用它来制作多人XNA游戏。

1 个答案:

答案 0 :(得分:0)

您可能希望尝试延长一段时间(或将它们全部移除;它们会给我带来麻烦)。此外,在处理主线程上的发送时,创建一个接收消息的线程确实是一个好主意。

一些注意事项:

你可以使用&#34; loopback&#34;或&#34; 127.0.0.1&#34;如果您想连接到本地IP

if (connectToIP == "self")
{
    connectToIP = localIPAddress(); 
    // if I want to test both on the same computer
}

你真的不应该连接,发送单个消息,然后断开连接,只是再次连接。

为客户尝试类似的事情:

using System.Threading;

    static void Main(string[] args)
    {
        TcpClient client = new TcpClient();

        Console.Write("IP: ");
        string ip = Console.ReadLine();
        Console.Write("Port: ");
        int port = int.Parse(Console.ReadLine());

        try
        {
            client.Connect(ip, port);
            StreamWriter sw = new StreamWriter(client.GetStream());
            sw.AutoFlush = true;
            StreamReader sr = new StreamReader(client.GetStream());
            Thread readThread = new Thread(() => readSocket(sr));
            readThread.Start(); //Run readSocket() at the same time
            string message = "";
            while (message != "exit")
            {
                message = Console.ReadLine();
                sw.WriteLine(message);
            }
            client.Close();
            return;                
        }
        catch (Exception e) { Console.WriteLine(e.ToString()); }
    }

    static void readSocket(StreamReader sr)
    {
        try
        {
            string message = "";
            while ((message = sr.ReadLine()) != null)
            {
                Console.WriteLine(message);
            }
        }
        catch (System.IO.IOException) { /*when we force close, this goes off, so ignore it*/ }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

以下是服务器的一个示例:

    static void Main(string[] args)
    {
        Console.Write("Port: ");
        int port = int.Parse(Console.ReadLine());
        TcpListener server = new TcpListener(IPAddress.Any, port);

        try
        {
            server.Start();
            TcpClient client = server.AcceptTcpClient();
            StreamWriter sw = new StreamWriter(client.GetStream());
            sw.AutoFlush = true;
            StreamReader sr = new StreamReader(client.GetStream());
            Thread readThread = new Thread(() => readSocket(sr));
            readThread.Start();
            string message = "";
            while (message != "exit")
            {
                message = Console.ReadLine();
                sw.WriteLine(message);
            }
            client.Close();
            return;                
        }
        catch (Exception e) { Console.WriteLine(e.ToString()); }
    }

    static void readSocket(StreamReader sr)
    {
        try
        {
            string message = "";
            while ((message = sr.ReadLine()) != null)
            {
                Console.WriteLine(message);
            }
        }
        catch (System.IO.IOException) { /*when we force close, this goes off, so ignore it*/ }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

Final Client and Server

以下是将消息转发给所有连接的客户端的异步服务器的代码(如果您担心无法共享端口)。

我试图让这些示例变得简单,但为所有这些示例添加更多异常处理可能是一个好主意。

class Server
{
    private int port;
    private Socket serverSocket;
    private List<StateObject> clientList;
    private const int DEFAULT_PORT = 1338;

    public Server()
    {
        this.port = 1338; //default port
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientList = new List<StateObject>();
    }

    public Server(int port)
    {
        this.port = port;
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientList = new List<StateObject>();
    }

    public void startListening(int port = DEFAULT_PORT)
    {
        this.port = port;
        serverSocket.Bind(new IPEndPoint(IPAddress.Any, this.port));
        serverSocket.Listen(1);
        serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
    }

    private void AcceptCallback(IAsyncResult AR)
    {
        try
        {
            StateObject state = new StateObject();
            state.workSocket = serverSocket.EndAccept(AR);
            //Console.WriteLine("Client Connected");
            clientList.Add(state);
            state.workSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
            serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
        }
        catch { }
    }

    private void ReceiveCallback(IAsyncResult AR)
    {
        StateObject state = (StateObject)AR.AsyncState;
        Socket s = state.workSocket;
        try
        {
            int received = s.EndReceive(AR);

            if (received == 0)
                return;

            if (received > 0)
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, received));

            string content = state.sb.ToString();

            if (content.IndexOf(Environment.NewLine) > -1)
            {
                //Console.WriteLine(content);
                foreach (StateObject others in clientList)
                    if (others != state)
                        others.workSocket.Send(Encoding.ASCII.GetBytes(content.ToCharArray()));
                state.sb.Clear();
            }

            Array.Clear(state.buffer, 0, StateObject.BufferSize);
            s.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
        }
        catch (Exception huh) {
            s.Close();
            s.Dispose();
            //Console.WriteLine("Client Disconnected");
            clientList.Remove(state);
            return;
        }
    }
    class StateObject
    {
        public Socket workSocket = null;
        public const int BufferSize = 1024;
        public byte[] buffer = new byte[BufferSize];
        public StringBuilder sb = new StringBuilder();
    }
}