2013-08-19 217 views
2

我已經建立了服務器和客戶端之間的連接,客戶端發送數據到服務器並接收響應,但我想從服務器發送數據到客戶端並接收客戶端到服務器的響應,是嗎可能嗎?這裏是我的代碼: [客戶]:TCP服務器到客戶端

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net.Sockets; 
using System.Net; 
using System.Text; 
using System.Threading.Tasks; 
using System.Threading; 

namespace Multi_Client 
{ 
    class Program 
    { 
     private static Socket _clientSocket = new Socket 
      (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

     static void Main(string[] args) 
     { 
      Console.Title = "Client"; 
      ConnectToServer(); 
      RequestLoop(); 
      Exit(); 
     } 

     private static void ConnectToServer() 
     { 
      int attempts = 0; 

      while (!_clientSocket.Connected) 
      { 
       try 
       { 
        attempts++; 
        Console.WriteLine("Connection attempt " + attempts); 
        _clientSocket.Connect(IPAddress.Loopback, 100); 
       } 
       catch (SocketException) 
       { 
        Console.Clear(); 
       } 
      } 

      Console.Clear(); 
      Console.WriteLine("Connected"); 
      _clientSocket.Send(Encoding.ASCII.GetBytes("C1")); 
     } 

     private static void RequestLoop() 
     { 
      Console.WriteLine(@"<Type ""exit"" to properly disconnect client>"); 

      SendRequest(); 
      ReceiveResponse(); 

     } 

     /// <summary> 
     /// Close socket and exit app 
     /// </summary> 
     private static void Exit() 
     { 
      SendString("exit"); // Tell the server we re exiting 
      _clientSocket.Shutdown(SocketShutdown.Both); 
      _clientSocket.Close(); 
      Environment.Exit(0); 
     } 

     private static void SendRequest() 
     { 
      Console.Write("Send a request: "); 
      string request = Console.ReadLine(); 
      SendString(request); 

      if (request.ToLower() == "exit") 
      { 
       Exit(); 
       return; 
      } 
     } 

     private static void SendString(string text) 
     { 
      byte[] buffer = Encoding.ASCII.GetBytes(text); 
      _clientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None); 
     } 

     private static void ReceiveResponse() 
     { 
      byte[] buffer = new byte[2048]; 
      int received = _clientSocket.Receive(buffer, SocketFlags.None); 

      if (received == 0) return; 

      byte[] data = new byte[received]; 
      Array.Copy(buffer, data, received); 
      string text = Encoding.ASCII.GetString(data); 
      Console.WriteLine(text); 
     } 
    } 
} 

[服務器]:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 
using System.Net; 
using System.IO; 
using NetworkCommsDotNet; 
using System.Net.Sockets; 

namespace Server 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 
     private static Socket _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     private static List<Socket> _clientSockets = new List<Socket>(); 
     private static readonly int _BUFFER_SIZE = 2048; 
     private static byte[] _buffer = new byte[_BUFFER_SIZE]; 
     string text; 
     Socket current; 
     Socket test; 
     delegate void SetTextCallback(string text); 

     private void SetText(string text) 
     { 
      // InvokeRequired required compares the thread ID of the 
      // calling thread to the thread ID of the creating thread. 
      // If these threads are different, it returns true. 
      if (this.richTextBox1.InvokeRequired) 
      { 
       SetTextCallback d = new SetTextCallback(SetText); 
       this.Invoke(d, new object[] { text }); 
      } 
      else 
      { 
       this.richTextBox1.Text += text + "\n"; 
      } 
     } 
     private void SetupServer() 
     { 
      SetText("Setting up server..."); 
      _serverSocket.Bind(new IPEndPoint(IPAddress.Any, 100)); 
      _serverSocket.Listen(5); 
      _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null); 
      SetText("Server Setup"); 
     } 

     /// <summary> 
     /// Close all connected client (we do not need to shutdown the server socket as its connections 
     /// are already closed with the clients) 
     /// </summary> 
     private static void CloseAllSockets() 
     { 
      foreach (Socket socket in _clientSockets) 
      { 
       socket.Shutdown(SocketShutdown.Both); 
       socket.Close(); 
      } 

      _serverSocket.Close(); 
     } 

     private void AcceptCallback(IAsyncResult AR) 
     { 
      Socket socket = null; 

      try 
      { 
       socket = _serverSocket.EndAccept(AR); 
      } 
      catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets) 
      { 
       return; 
      } 

      _clientSockets.Add(socket); 
      socket.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket); 
      SetText("Client connected, waiting for request..."); 
      test = (Socket)AR.AsyncState; 
      _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null); 
     } 
     private void ReceiveCallback(IAsyncResult AR) 
     { 
      current = (Socket)AR.AsyncState; 
      int received = 0; 

      try 
      { 
       received = current.EndReceive(AR); 
      } 
      catch (SocketException) 
      { 
       SetText("Client forcefully disconnected"); 
       current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway 
       _clientSockets.Remove(current); 
       return; 
      } 

      byte[] recBuf = new byte[received]; 
      Array.Copy(_buffer, recBuf, received); 
      text = Encoding.ASCII.GetString(recBuf); 
      SetText("Received Text: " + text); 
      if (text.ToLower() == "get tim") // Client requested time 
      { 
       SetText("Text is a get time request"); 
       byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString()); 
       current.Send(data); 
       SetText("Time sent to client"); 
      } 
      else if (text.ToString() == "C1") // Client wants to exit gracefully 
      { 
       SetText("Received :: C1"); 
       byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString()); 
       current.Send(data); 
      } 

      else 
      { 
       SetText("Server is sending invalid packet"); 
       SetText("Warning Sent"); 
      } 
      current.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, new AsyncCallback(ReceiveCallback), current); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      SetupServer(); 
     } 
     private void Send_Received(string mess) 
     { 
      byte[] data = Encoding.ASCII.GetBytes(mess); 
      test.Send(data); 
     } 
     private void button2_Click(object sender, EventArgs e) 
     { 
      CloseAllSockets(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      Send_Received(textBox1.Text); 
     } 


    } 
} 
+1

你需要解釋你做了什麼,以及爲什麼它不工作。您留下的代碼轉儲的大小足夠大,以至於沒有人可能會潛入並嘗試從您寫的很少的東西中弄清楚什麼。 –

+0

好吧,我被封鎖了,我不知道如何在客戶端向服務器發送任何數據之前將數據從服務器發送到客戶端 – user2695010

回答

3

簡短的回答:是的,這是可能的。

長:有。您當前的代碼以這種方式實現:

  • 服務器初始化並準備接收連接。
  • 客戶端嘗試連接。
  • 服務器接受連接,添加到clientSockets集合。
  • 客戶端發送「C1」。
  • 服務器接收內容,解釋併發回答案。
  • 客戶收到答案。

然後你進入一個循環,因爲沒有其他內容被髮送。您實現了一個同步協議 - 客戶端會話,服務器迴應,客戶端將其轉存到控制檯。

讓我提出的快速實現,因此您可以測試服務器 - >客戶端 - >服務器交換:

  • 實現您的服務器上的異步定時器。
  • 10秒鐘後,如果沒有傳入消息從特定客戶端到達,請發送「PING?」消息。
  • 解析客戶端上的傳入內容。如果消息等於「PING?」,則用「PONG!」回答。

這是一個非常簡單的QoS協議 - 您將測試連接的健康狀況。

讓我們知道你是否設法實現它。 =)

+0

非常感謝您的回答!我要檢查所有這些,並讓你知道是否結果。 – user2695010

+0

不客氣:異步通信學習起來可能有點棘手,但一旦掌握了它,對於SaaS(系統即服務)解決方案而言,記住它是一個很好的概念。 – OnoSendai

+0

實際上,如果沒有客戶端向服務器發送內容,Socket變量爲空,所以當服務器發送數據時,它顯示「對象引用未設置爲對象的實例」,並且再次感謝你,很棒! – user2695010

0

其實,我知道問題出在哪裏,當服務器送東西到客戶端和客戶端尚未發送的東西,客戶端不顯示的東西,直到他送到另一個東西:O型 例(我知道它很複雜): 服務器發送C1並在控制檯C1中顯示發送給客戶端:客戶端什麼都不做(他應該在控制檯C1O中顯示) 客戶端發送Pa(隨機)並在控制檯中顯示CAO:服務器接收Pa 客戶端發送Ka(隨機)並顯示在控制檯(無效的請求,因爲服務器已收到Pa,因此它發送無效的請求文本) 即使我知道它不是:S

0

我解決它通過編輯RequestLoop功能:

private static void RequestLoop() 
    { 
     ReceiveResponse(); 

    } 

它`所有:)