[英]C# .Net Socket Server Client
我對 C# 中的 .Net 套接字有一點問題。 我編寫了一個使用 TCP 的客戶端和一個服務器。
當客戶端打開時,它會向服務器發送握手。 服務器用它的狀態(clientexists,clientaccepted,...)回答。 之后,應用程序發送一個 getdata 請求,放棄連接並偵聽服務器的“響應”。 現在,服務器建立到客戶端的連接並發送客戶端需要的所有數據。
代碼和其他一切都有效,但問題是:
在我們公司的測試服務器上它工作正常,在實時服務器上只有握手工作。 之后,客戶端不再接收任何數據。 服務器應用程序在兩台服務器上是相同的。
我認為問題是由某些防火牆引起的(服務器想要與客戶端建立 tcp 連接 -> 不好),但系統管理員說沒有防火牆可以阻止它。
現在我正在尋找一種(“便宜”)解決方案,它不會花費太多時間和代碼更改。 如果有人知道如何從理論上解決這個問題,那就太好了。
順便說一句:除了運行服務器應用程序之外,我不允許在實時服務器上做任何事情。 我無法在此服務器上進行調試。
我無法發布我的所有代碼,但如果您需要查看其中的特定部分,請索取。
- -編輯 - -
客戶端-服務器通信
1) 客戶端啟動
客戶端發送握手(新的 tcp 連接)
2)服務器驗證握手並保存IP
服務器以其客戶端狀態響應(相同的 tcp 連接)
3) 客戶端確認此響應並放棄此連接
客戶端發送 getdata-request(新的 tcp 連接)
客戶端也放棄了這個 tcp 連接
4)服務器接收getdata-request,在主庫中收集需要的數據
服務器將所有收集到的數據發送給客戶端(多個 tcp 連接)
5) 客戶端接收所有數據並將其顯示在它的 GUI 中(多個 tcp 連接和數據的順序通過使用 AutoResetEvents 和要發送的套接字計數來保持)
這是我的代碼所做的主要部分。 到目前為止,它不是最好的,但我猜它是為我寫的。 第一步、第二步和第三步按預期工作。 數據的處理也很好。 我忘記提及的另一件事是該解決方案使用兩個端口“16777”和“16778”。 一個接收/收聽,一個發送。 我的代碼基於異步服務器和客戶端的 MSDN 示例。
發送握手(和 getdata-request)
public void BeginSend(String data)
{
try
{
StateObject state = new StateObject();
state.workSocket = sender;
byte[] byteData = Encoding.UTF8.GetBytes(data);
sender.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback((IAsyncResult e) =>
{
Socket socket = (Socket)e.AsyncState;
SocketBase.StateObject stateObject = new SocketBase.StateObject();
stateObject.workSocket = socket;
socket.BeginReceive(stateObject.buffer, 0, 256, SocketFlags.None, new AsyncCallback(this.ReadCallback), (object)stateObject);
}), sender);
sender = RetrieveSocket(); //Socketreset
Thread.Sleep(100);
}
catch /*(Exception e)*/
{
//--
}
}
服務器偵聽器
public void StartListening()
{
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(System.Int32.MaxValue);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
//--
}
}
public void AcceptCallback(...);
public void ReadCallback(...);
套接字發送
private void Send(Socket handler, String data)
{
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.UTF8.GetBytes(data);
// Begin sending the data to the remote device.
t.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), t);
}
Socket發送所有數據部分(getdata-request | socToHandle的回答應該是getdata-request的前一個連接的socket)
private void SendAllData(Socket socToHandle, string PakContent)
{
#region IsThereADatetime? //Resolve a given datetime
#region GiveClientNumberOfPackets //Send the client info about how much he has to receive (See line below)
Send(socToHandle, "ALERT#TASKCOUNT;OPT-" + GetBestDate(dateStart) + EndSocket);
#region #SendResouces
#region #SendGroups
#region #SendTasks
}
查看我的舊代碼,我有一個想法 =>
我可以通過更改通過同一連接發送所有內容:
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
(創建一個新連接)到使用相同連接的東西? 如果那行得通,我該怎么做? 客戶端的偵聽器部分還會收到單個數據包嗎?
服務器及其環境配置為正確處理傳入請求。 客戶端通常位於路由器后面,默認情況下,這使它們無法接收來自網絡外部的傳入連接(一件好事)。
要啟用傳入連接,您可以將路由器配置為將特定端口號的所有請求轉發到您的機器。 但是,您網絡上的其他人將無法運行客戶端。
這就是為什么在典型的多客戶端-單服務器環境中,客戶端進行所有連接,並且只有服務器需要對網絡格局進行任何更改。
我不知道你為什么選擇從服務器端連接到客戶端,但我強烈建議不要這樣做 - 任何使用這種機制的廉價解決方案最終可能會變得非常昂貴。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.