“开发可以安装在办公室或企业的各种Windows机器上的Windows窗体应用程序.只有一台机器(ALPHA机器)就有一个数据库.这个数据库将被其他Beta机器上的应用程序用来访问数据应用程序本身会设法检查它是Alpha还是Beta(包含数据库文件?),因此必须充当服务器或客户端.“
除网络和应用程序间通信要求外,我可以做任何事情.所以,我开始通过互联网学习Socket编程,我已经完成了this link …
我正在研究的想法是……
>让客户端将消息发送到服务器.
>让服务器接受此消息并将此消息放入队列中.
>阅读邮件以获取客户的IP地址及其数据请求.
>在数据库上应用此请求并获取结果.
>将结果转换为字符串.
>将其发送给请求客户端.
我可以设法执行步骤3,4和我被困在1,2和2上. 6.
走向这……
我已经为Server以及在调用时返回套接字的客户端创建了一个函数.我创建了一个单独的函数,因为我喜欢我的代码,干净,整洁,多年后可以理解.
检查下面的代码……
对于服务器……
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,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?",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",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.",MessageBoxIcon.Error); } streamWriter.Close(); networkStream.Close(); socketForServer.Close(); }
>“txtBxDestIP”是具有目标IP地址为Text的TextBox.
>“txtBxData”是具有要发送的文本的TextBox.
这段代码对我来说完美无瑕.通过上述解决方案,我可以实现从步骤1到6的所有动机(在上面的问题中提到.)
我希望它也有助于其他人.请建议是否有更好,更有效的方法来执行此操作.
谢谢.问候.