我有一个客户端 - 服务器应用程序 服务器可以处理多个客户端连接。
当我单击客户端中的Close
按钮时,我希望它被断开连接,并从服务器表单中的客户端列表中删除。
然而,它进入一个无限循环,导致客户端从表单的ListView
中删除,然后再次添加到表单的ListView
。
这是我的代码:
RemoteBatcherClientForm :
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.Net;
using System.Net.Sockets;
namespace RemoteBatcherClient
{
public partial class RemoteBatcherClientForm : Form
{
Socket clientSock;
public RemoteBatcherClientForm()
{
InitializeComponent();
clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
private void connectBtn_Click(object sender, EventArgs e)
{
clientSock.Connect("127.0.0.1", 8);
MessageBox.Show("Connected");
}
private void sendBtn_Click(object sender, EventArgs e)
{
if (clientSock.Send(Encoding.Default.GetBytes(txtMsg.Text)) > 0)
{
MessageBox.Show("Data Sent");
}
}
private void closeBtn_Click(object sender, EventArgs e)
{
clientSock.Close();
clientSock.Dispose();
Close();
}
}
}
RemoteBatcherServer :
Client.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace RemoteBatcherServer
{
class Client
{
public string ID
{
get;
private set;
}
public IPEndPoint EndPoint
{
get;
private set;
}
Socket serverSock;
public Client(Socket accepted)
{
serverSock = accepted;
ID = Guid.NewGuid().ToString();
EndPoint = (IPEndPoint)serverSock.RemoteEndPoint;
serverSock.BeginReceive(new byte[] { 0 }, 0, 0, 0, callback, null);
}
void callback(IAsyncResult ar)
{
try
{
serverSock.EndReceive(ar);
byte[] receiveBuffer = new byte[8192];
int rec = serverSock.Receive(receiveBuffer, receiveBuffer.Length, 0);
if (rec < receiveBuffer.Length)
{
Array.Resize<byte>(ref receiveBuffer, rec);
}
if (Receieved != null)
{
Receieved(this, receiveBuffer);
}
serverSock.BeginReceive(new byte [] {0}, 0, 0, 0, callback, null);
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
Close();
if (Disconnected != null)
{
Disconnected(this);
}
}
}
public void Close()
{
serverSock.Close();
serverSock.Dispose();
}
public delegate void ClientReceievedHandler(Client sender, byte[] data);
public delegate void ClientDisconnectedHandler(Client sender);
public event ClientReceievedHandler Receieved;
public event ClientDisconnectedHandler Disconnected;
}
}
Listener.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace RemoteBatcherServer
{
class Listener
{
Socket sck;
public bool Listening
{
get;
private set;
}
public int Port
{
get;
private set;
}
public Listener(int port)
{
Port = port;
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public void Start()
{
if (Listening)
return;
sck.Bind(new IPEndPoint(0, Port));
sck.Listen(0);
sck.BeginAccept(callback, null);
Listening = true;
}
public void Stop()
{
if (!Listening)
return;
sck.Close();
sck.Dispose();
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
void callback(IAsyncResult ar)
{
try
{
Socket acceptSocket = sck.EndAccept(ar);
if (SockeetAccepted != null)
{
SockeetAccepted(acceptSocket);
}
sck.BeginAccept(callback, null);
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public delegate void SocketAcceptHandler(Socket acceptSocket);
public event SocketAcceptHandler SockeetAccepted;
}
}
RemoteBatcherServerForm.cs:
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.Net;
using System.Net.Sockets;
namespace RemoteBatcherServer
{
public partial class RemoteBatcherServerForm : Form
{
Listener listener;
public RemoteBatcherServerForm()
{
InitializeComponent();
listener = new Listener(8);
listener.SockeetAccepted += new Listener.SocketAcceptHandler(listenerSocketAccepted);
Load += new EventHandler(MainLoad);
}
void MainLoad(object sender, EventArgs e)
{
listener.Start();
}
void listenerSocketAccepted(Socket socket)
{
Client client = new Client(socket);
client.Receieved += new Client.ClientReceievedHandler(clientReceived);
client.Disconnected += new Client.ClientDisconnectedHandler(clientDisconnected);
Invoke((MethodInvoker)delegate
{
ListViewItem item = new ListViewItem();
item.Text = client.EndPoint.ToString();
item.SubItems.Add(client.ID);
item.SubItems.Add("XX");
item.SubItems.Add("XX");
item.Tag = client;
lstClients.Items.Add(item);
});
}
void clientReceived(Client sender, byte[] data)
{
Invoke((MethodInvoker)delegate
{
for (int i = 0; i < lstClients.Items.Count; i++)
{
Client client = lstClients.Items[i].Tag as Client;
if (client.ID == sender.ID)
{
lstClients.Items[i].SubItems[2].Text = Encoding.Default.GetString(data);
lstClients.Items[i].SubItems[3].Text = DateTime.Now.ToString();
break;
}
}
});
}
void clientDisconnected(Client sender)
{
Invoke((MethodInvoker)delegate
{
for (int i = 0; i < lstClients.Items.Count; i++)
{
Client client = lstClients.Items[i].Tag as Client;
if (client.ID == sender.ID)
{
lstClients.Items.RemoveAt(i);
break;
}
}
});
}
}
}
有什么想法吗?
答案 0 :(得分:0)
除非我误解你的代码,否则你似乎混合了同步和异步调用。我认为你无限期地使用serverSock.Receive调用阻塞。请参阅:http://msdn.microsoft.com/en-us/library/8s4y8aff.aspx - “如果没有可用于读取的数据,则接收方法将阻塞,直到数据可用,除非使用Socket.ReceiveTimeout设置超时值”
serverSock.EndReceive(ar);
byte[] receiveBuffer = new byte[8192];
int rec = serverSock.Receive(receiveBuffer, receiveBuffer.Length, 0);
尝试检查是否收到了0个字节。您可能还想换掉BeginReceive的接收调用。它可能看起来有点令人困惑,因为你实际上想要继续重新调用BeginReceive,直到你收到0个字节,表明另一方已经关闭了连接:
int i = serverSock.EndReceive(ar);
if (i > 0)
{
serverSock.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, 0,
new AsyncCallback(callback), null);
}
else
{
serverSock.Close();
}
注意,您可以为传递的状态对象交换null参数。您可以在Client构造函数中的初始BeginReceive调用中执行此操作 - 这可能是传递缓冲区的更好方法,使用某种State类包装它。
答案 1 :(得分:0)
以下是一个快速回答:修改Client.cs
的{{1}}方法,以检查Socket.Available Property是否返回0(当客户端关闭时会发生这种情况):
void callback(IAsyncResult ar)