最近,我接到了一个任务......
“开发一个 Windows 窗体应用程序,它可以安装在办公室或企业的各种 Windows 机器上。只有一台机器(ALPHA 机器)上会有一个数据库。其他 Beta 机器上的应用程序将使用该数据库访问数据。应用程序本身会设法检查它是 Alpha 版还是 Beta 版(是否包含数据库文件?),因此必须充当服务器或客户端。”
除了网络和应用程序间通信要求外,我可以做所有事情。所以,我开始通过互联网学习套接字编程,我经历了this link ...
我正在研究的想法是...
- 让客户端向服务器发送消息。
- 让服务器接受此消息并将此消息放入队列。
- 阅读消息以获取客户的 IP 地址及其数据请求。
- 将此请求应用于数据库并获取结果。
- 将结果转换为字符串。
- 将其发送给提出请求的客户。
我可以设法执行步骤 3、4 和 5。我卡在了 1、2 和 6 上。
朝着这个...
我已经为服务器以及在调用时返回套接字的客户端创建了一个函数。我创建了一个单独的函数,因为我希望我的代码在多年后保持干净、整洁和易于理解。
检查下面我的代码...
对于服务器...
private Socket GetServerReady()
{
IPEndPoint RemoteEP = new IPEndPoint(IPAddress.Any, 8000);
Socket newSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
newSock.Connect(RemoteEP);
newSock.Listen(10);
return (newSock);
}
你会注意到任何地方都没有 Accept() 方法,这是因为我想像下面这样调用它以供进一步使用...
Socket CltSock = GetServerReady().Accept();
客户端代码是...
private Socket GetClientReady()
{
IPEndPoint RemoteEP = new IPEndPoint(IPAddress.Parse(txtBxHost2.Text.Trim()), 8000);
Socket ServerSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
ServerSock.Connect(RemoteEP);
return (ServerSock);
}
最后,问题是......
“调用我上面写的函数的合适位置在哪里?”
“我应该在 Form_Load() 事件中调用服务器和客户端函数吗?”
“我的主要意图(即上述第 1、2 和 6 点)的下一步必须是什么?”
我不希望我可以按原样复制完整的代码。只要正确的程序和概念的一些细节就可以了。
我将只使用一台 PC 进行测试。此外,另一个限制是,它将全部编码在一个应用程序中。我不想为客户端和服务器编写两个单独的应用程序。
我希望我说的很清楚,以便您理解。
非常感谢。
等待响应。
最佳答案
我一直在努力完成事情,并以某种方式设法找到了解决方案。
下面是我的解决方案:
服务器端代码: (我将这段代码放在一个函数中,如果捕获到任何异常,该函数会循环执行)
private void Looper()
{
int i = 0;
int AttemptCount = 1;
while (i == 0)
{
try
{
TcpListener tL = new TcpListener(Network.GetLocalIPAddress(), 56009);
tL.Start(10);
Socket tS = tL.AcceptSocket();
if (tS.Connected)
{
NetworkStream nS = new NetworkStream(tS);
StreamReader Reader = new StreamReader(nS);
Output = Reader.ReadToEnd().Trim();
Reader.Close();
nS.Close();
tS.Close();
tL.Stop();
//If Done, End Execution
i = 1;
}
else
{
MessageBox.Show("The connection to the client is broken or failed..!!\n\nPlease check connection and try again.","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}
catch (SystemException ex)
{
//If Not, Loop Execution Again
if (MessageBox.Show("Exception: " + ex.Message + "\n\nAttempt Count: " + AttemptCount + "\n\nDo you want to terminate the transmission?", "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.Yes)
{
i = 1;
ResetTimer.Stop();
}
else
{
i = 0;
AttemptCount++;
}
}
}
}
当调用上述函数时,服务器等待接受任何传入的套接字。如果由于端口重新使用或其他原因导致某处出现任何错误,它会自行循环并重置服务器。 (因此,我们不必一次又一次地手动调用服务器函数。)
一旦服务器接受任何传入的套接字,执行就会成功结束。很多时候我们不想在成功接收后继续调用服务器。所以,我没有在按钮“click_event”中调用此函数,而是在计时器 Tick_Event 中调用它。因此,在服务器端消除了人为需求。
这导致了一个问题。一旦服务器开始等待接受,它就处于阻塞模式。 它将所有进程和控件卡在同一个线程中。因此,我将对上述函数的调用移到了 BackgroundWorker 的“Do_Work”事件中。
检查下面的代码:
private void GetServerReady()
{
if (!bW.IsBusy)
{
bW.RunWorkerAsync();
txtBxHistory.Text += "\r\n" + Output;
}
}
private void bW_DoWork(object sender, DoWorkEventArgs e)
{
Looper();
}
private void ResetTimer_Tick(object sender, EventArgs e)
{
GetServerReady();
}
- “bW”是“BackgroundWorker”。
- “输出”是我在全局定义的变量。
我们需要一个变量的原因是,
BackgroundWorker 有自己的线程来执行放置在其“Do_Work”事件中的代码。因此,BackgroundWorker 无法使用应用程序线程中的 TextBox 来存储接收到的输出。对变量执行此操作,然后将 TextBox 的 Text 属性设置为此变量即可。
客户端代码:
private void btnSend_Click(object sender, EventArgs e)
{
TcpClient socketForServer;
try
{
socketForServer = new TcpClient(txtBxDestIP.Text.Trim(), 56009);
}
catch
{
MessageBox.Show("Failed to connect to server at " + txtBxDestIP.Text.Trim() + ":999", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
NetworkStream networkStream = socketForServer.GetStream();
StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
try
{
string InputString;
InputString = Network.GetLocalIPAddress() + ": " + txtBxData.Text;
streamWriter.Write(InputString);
streamWriter.Flush();
socketForServer.Close();
txtBxHistory.Text += "\r\nMe: " + txtBxData.Text.Trim();
txtBxData.Clear();
}
catch
{
MessageBox.Show("Exception reading from Server.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
streamWriter.Close();
networkStream.Close();
socketForServer.Close();
}
- “txtBxDestIP”是一个文本框,目标 IP 地址为文本。
- “txtBxData”是一个包含要发送的文本的文本框。
这段代码对我来说完美无缺。通过上述解决方案,我可以实现从第 1 步到第 6 步的所有动机(在上面的问题中提到。)
希望对其他人也有帮助。请建议是否有更好、更有效的方法来执行此操作。
谢谢。 问候。
关于c# - 使用 Visual C# (Dot Net Framework 4.0) 在 "Socket Programming"中需要帮助?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16730939/