c# - TCP-IP 客户端-服务器应用程序来操作字典
问题描述
我正在编写一个客户端-服务器程序。
服务器将保存一个字典,客户端可以将更新键值添加到字典中。
假设客户“A”添加了一个项目(1, 111)
。当另一个客户端“B”想要更新 的值时(1, 111)
,它必须寻求“A”的确认,反之亦然。
请看下面的程序:
using MyClientServerLib;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MyServerProgram
{
class ServerProgram
{
static Dictionary<string, KeyValue> KeyValueDictionary;
static Dictionary<string, ClientClass> ClientDictionary;
static void Main(string[] args)
{
Console.Title = "Server";
Console.WriteLine("Server program started...");
KeyValueDictionary = new Dictionary<string, KeyValue>();
ClientDictionary = new Dictionary<string, ClientClass>();
string ipAddress = "127.0.0.1";
int portNo = 2000;
IPAddress ip = IPAddress.Parse(ipAddress);
TcpListener listener = new TcpListener(ip, portNo);
// poll for clients in a 2nd thread
Thread thread = new Thread(delegate()
{
ServerProgram.PollIncomingClientConns(listener);
});
thread.Start();
}
#region catching client connections
static void PollIncomingClientConns(TcpListener listener)
{
listener.Start();
try
{
bool keepRunning = true;
while (keepRunning)
{
ClientClass client = new ClientClass(listener);
ClientDictionary.Add(client.ID, client);
Thread thread = new Thread(delegate()
{
ServerProgram.ReadFromClient(client);
});
thread.Start();
}
}
catch (Exception ex)
{
var inner = ex.InnerException as SocketException;
if (inner != null && inner.SocketErrorCode == SocketError.ConnectionReset)
Console.WriteLine("Disconnected");
else
Console.WriteLine(ex.Message);
listener.Stop();
}
}
#endregion
static void ReadFromClient(ClientClass client)
{
try
{
ClientClass origClient = null;
while (client.Tcp.Connected)
{
string str = client.ReadString();
switch(str)
{
case Commands.AddKeyValue:
string key = client.ReadString();
string val = client.ReadString();
KeyValue keyValue = new KeyValue(client.ID, key, val);
KeyValueDictionary.Add(key, keyValue);
Console.WriteLine(keyValue.ToString() + " added.");
break;
case Commands.ListKeys:
if (KeyValueDictionary.Keys.Count > 0)
{
foreach (string key1 in KeyValueDictionary.Keys)
{
client.Write("(" + key1 + "," + KeyValueDictionary[key1].Value + ")\t");
}
}
else
{
client.Write("No KV");
}
break;
case Commands.UpdateValue: //obtain update requester client-ID
client.Key = client.ReadString(); //read key
client.Value = client.ReadString(); //read val
KeyValue oldKeyVal = null;
bool currClientFound = KeyValueDictionary.TryGetValue(client.Key, out oldKeyVal); //search the dictionary with the client name
if (currClientFound) //if found
{
if (oldKeyVal.ClientID.Equals(client.ID))//if rem requested by same client...
{
KeyValueDictionary[client.Key].Value = client.Value;
client.Write(client.Key + " is updated.");
}
else //if rem requested by a different client...
{
//get the original client
bool origClientFound = ClientDictionary.TryGetValue(oldKeyVal.ClientID, out origClient); //search the dictionary with the client name
if (origClientFound)
{
origClient.Write(client.ID + " wants to change " + oldKeyVal.ToString() + "(y/n)");
}
}
}
break;
case Commands.Yes:
Console.WriteLine(client.Key + ", " + client.Value);
KeyValueDictionary[client.Key].Value = client.Value;
client.Write(client.Key + " is updated.");
break;
}
}
}
catch
{
client.Disconnect();
}
}
}
}
问题出在case Commands.UpdateValue
和中case Commands.Yes
。
当客户端在先前的迭代中请求更新时,键值对与客户端实例一起保存。然后,在下一次迭代中,当另一个客户端发送确认时,键值对被更新。
但是,在下一次迭代中,client.Key
显示null
. 因此case Commands.Yes
是失败的。
我该如何解决这个问题?
附加源代码文件:
解决方案
我通过使键和值保持变量静态来解决这个问题:
class ServerProgram
{
static stKey;
static stValue;
....
....
case Commands.UpdateValue: //obtain update requester client-ID
stKey = client.ReadString(); //read key
stValue = client.ReadString(); //read val
....
....
case Commands.Yes:
Console.WriteLine(stKey + ", " + stValue);
KeyValueDictionary[stKey].Value = stValue;
client.Write(stKey + " is updated.");
break;
}
推荐阅读
- python - Google Developer API 使用 Python 上传 APK
- python - 为什么我有 python 错误 unindent does not match any external indentation level 错误
- android - android:kotlin:实现分页3时数据未加载到适配器中
- haskell - 给定一个列表,如何仅对每两个元素满足二元谓词的子列表执行一些转换?
- c# - 创建自定义可序列化值类型
- sql-server - 如何使用 SQL Server 从数据库中获取具有列的表的特定列中的所有表名和不同值
- palantir-foundry - 为什么我不应该在我的 Python 转换中使用 collect()?
- spring-boot - 在不启动服务器的情况下使用 Spring 应用程序属性
- apache-nifi - 如何在 NiFi 处理器中重新加载外部配置数据
- php - 上传图片或创建新帖子时,Wordpress 中的 net::ERR_CONNECTION_RESET