希望实现的功能:1.实时的现实所有的客户端是否在线,即一开启程序,就检测所有的客户端,把在线的彩色现实,并都排在前面;不在线的都灰色现实,都排在后面。要求一定要用异步的实现。
现在我用异步的方式出现的问题是:1.当客户端程序第一次运行时,服务器端程序才会检测到客户端是否在线,并把他彩色或灰色显示。但关掉客户端程序再次启动时,服务器端程序就不去检测客户端是否在线了。(这个问题让我很郁闷) 2.(这个问题有时会出现)当关掉客户端程序再次启动时,会弹出“什么端口只能使用一次”的异常(记不太清了,明天会补详细点)。不知道我出现的问题有没有人碰到过?
明天我会把代码贴出来的。
现在我用异步的方式出现的问题是:1.当客户端程序第一次运行时,服务器端程序才会检测到客户端是否在线,并把他彩色或灰色显示。但关掉客户端程序再次启动时,服务器端程序就不去检测客户端是否在线了。(这个问题让我很郁闷) 2.(这个问题有时会出现)当关掉客户端程序再次启动时,会弹出“什么端口只能使用一次”的异常(记不太清了,明天会补详细点)。不知道我出现的问题有没有人碰到过?
明天我会把代码贴出来的。
2.这个涉及到端口重用的问题,你可以使用端口重用参数设置Socket,或者断开时设定立即断开连接.
1、客户端掉线时(或关闭时),服务端没有及时得知其已下线,并及时刷新其状态显示;解决办法:通过设置Socket低级参数,使得服务端及时得知掉线;
通过客户端关闭时发送下线消息给服务端进行通知;2、可能程序上不小心设置了接受同一个客户端连接时,使用了同一个端口,这将导致同一个客户端快速断线重连时,服务端出现那个错误解决办法:
对每一个客户端连接,都使用随机端口,而非固定端口
写完了发现问题2有点问题按理说Scoket服务端在同一个端口上侦听连接,收到了就创建Socket实例,服务端的端口是始终不变的。不应该出现这个情况。疑惑是不是你的“服务”实际上是Socket客户端而你的“客户”实际上是Sokcet服务端?Socekt服务端负责Listen
SOcket客户端负责Connect
namespace WpfServer1
{
public partial class Window1 : Window
{
private int listenport = 5555;
private StateObject state;
private Socket _svrSock;
private static ManualResetEvent Done = new ManualResetEvent(false); //用来把在线不在线分开显示的
public ArrayList list = new ArrayList();//存储在线的用户socket
public ObservableCollection<Machines> _machineItem = new ObservableCollection<Machines>();
string FilePath = AppDomain.CurrentDomain.BaseDirectory.ToString() + @"\Machine.xml";
private delegate void SetListView(); private void Window_Loaded(object sender, RoutedEventArgs e)
{
if (File.Exists(FilePath))
{
_machineItem = GetLocalMachineItems();
lstClients.ItemsSource = _machineItem;
} Thread th = new Thread(new ThreadStart(StartListening));
th.Start();
} // 获得所有的播放机,并让其初始化时图片为灰色
public ObservableCollection<Machines> GetLocalMachineItems()
{
ObservableCollection<Machines> lst = new ObservableCollection<Machines>();
XmlDocument doc = new XmlDocument();
doc.Load("Machine.xml");
foreach (XmlNode node in doc.SelectSingleNode("groups").ChildNodes)
{
lst.Add(new Machines("Images/ComputerGray.png", node));
}
return lst;
} //开始连接
public void StartListening()
{
while (true)
{
IPAddress myipAddress = Dns.GetHostAddresses(Dns.GetHostName())[0];
IPEndPoint localEndPoint = new IPEndPoint(myipAddress, listenport);
_svrSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
_svrSock.Bind(localEndPoint);
_svrSock.Listen(100);
_svrSock.BeginAccept(new AsyncCallback(AcceptCallback), _svrSock);
}
catch { }
}
} public void AcceptCallback(IAsyncResult ar)
{
//Done.Set();
try
{
Socket serverSock = (Socket)ar.AsyncState;
Socket clientSock = serverSock.EndAccept(ar);
state = new StateObject();
state.workSocket = clientSock; byte[] bytedata = System.Text.Encoding.BigEndianUnicode.GetBytes("1");
clientSock.BeginSend(bytedata, 0, bytedata.Length, 0, new AsyncCallback(SendCallback), clientSock); clientSock.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch (Exception ex){MessageBox.Show(ex.Message, "服务器提示");}
} public void SendCallback(IAsyncResult ar)
{
try
{
Socket clientSocket = (Socket)ar.AsyncState;
int bytesSent = clientSocket.EndSend(ar);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
} public void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket clientSocket = state.workSocket;
int bytesRead = clientSocket.EndReceive(ar);
string strF = System.Text.Encoding.BigEndianUnicode.GetString(state.buffer,0,bytesRead);
string[] tokens = strF.Split(new char[] { '|' });
string before = tokens[1];
string after = Regex.Replace(tokens[1], "[0-9.]", "");
tokens[1] = tokens[1].Substring(0, before.Length - after.Length); if (bytesRead == 0)
{
return;
}
else
{
try
{//下面是根据客户端发的消息对其作出在线或不在线的处理
if (tokens[0].ToString() == "CONN")
{
for (int i = 0; i < lstClients.Items.Count; i++)
{
Machines machine = (Machines)lstClients.Items[i];
if (machine.Ip == tokens[1] && machine.ImgSource == "Images/ComputerGray.png")
{
machine.ImgSource = "Images/ComputerLight.png";
list.Add(clientSocket);
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
break;
}
}
Dispatcher.Invoke((SetListView)delegate { SetRefresh(); }, new object[] { });
}
else if (tokens[0].ToString() == "GONE")
{
for (int i = 0; i < lstClients.Items.Count; i++)
{
Machines machine = (Machines)lstClients.Items[i];
if (machine.Ip == tokens[1] && machine.ImgSource == "Images/ComputerLight.png")
{
machine.ImgSource = "Images/ComputerGray.png";
list.Remove(clientSocket);
break;
}
}
Dispatcher.Invoke((SetListView)delegate { SetRefresh(); }, new object[] { });
clientSocket.Close();
}
else
{
for (int i = 0; i < lstClients.Items.Count; i++)
{
Machines machine = (Machines)lstClients.Items[i];
if (machine.Ip == tokens[1] && machine.ImgSource == "Images/ComputerLight.png")
{
machine.ImgSource = "Images/ComputerGray.png";
list.Remove(clientSocket);
break;
}
}
Dispatcher.Invoke((SetListView)delegate { SetRefresh(); }, new object[] { });
clientSocket.Close();
}
}
catch (Exception ee){MessageBox.Show(ee.Message);}
}
} //线程调用控件
private void SetRefresh()
{
lstClients.Items.Refresh();
SortList();
} //排序用户,图片高亮的显示在前
private void SortList()
{
ICollectionView view = GetView();
view.SortDescriptions.Add(new SortDescription("ImgSource", ListSortDirection.Descending));
} public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 64 * 1024;
public byte[] buffer = new byte[BufferSize];
public int isOnLine;//2表示在线,1,0表示不在线;
} //获取Listview数据源的视图
ICollectionView GetView()
{
return CollectionViewSource.GetDefaultView(_machineItem);
}
}
}
namespace WindowsClient1
{
public partial class Form1 : Form
{
private StateObject state;
private delegate void SetTextCallBack(string str); private System.ComponentModel.IContainer components = null; /// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
} private void Form1_Load(object sender, EventArgs e)
{
try
{
IPAddress ipAddress = Dns.GetHostAddresses(Dns.GetHostName())[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 5555);
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), clientSocket);
}
catch (Exception ee)
{
MessageBox.Show(ee.Message, "客户端提示");
} } private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket clientSock = (Socket)ar.AsyncState;
clientSock.EndConnect(ar);
state = new StateObject();
state.workSocket = clientSock;
string data = "CONN|" + Dns.GetHostAddresses(Dns.GetHostName())[0].ToString();
byte[] byteData = System.Text.Encoding.BigEndianUnicode.GetBytes(data);
clientSock.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), clientSock);
clientSock.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch (Exception ee) { MessageBox.Show(ee.Message, "客户端提示"); }
} private void SetText(string str)
{
if (richTextBox3.InvokeRequired)
{
SetTextCallBack st = new SetTextCallBack(SetText);
this.Invoke(st, new object[] { str });
}
else
richTextBox3.AppendText(str);
} private void ReadCallback(IAsyncResult ai)
{
try
{
StateObject state = (StateObject)ai.AsyncState;
Socket client = state.workSocket;
int byteread = client.EndReceive(ai);
string strF = System.Text.Encoding.BigEndianUnicode.GetString(state.buffer, 0, byteread);
if (strF != "")
{
SetText("来自服务器的消息:" + strF);
}
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch (Exception ee) { MessageBox.Show(ee.Message, "客户端提示"); }
} private void SendCallback(IAsyncResult ar)
{
try
{
Socket clientSocket = (Socket)ar.AsyncState;
int bytesSent = clientSocket.EndSend(ar);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "客户端提示");
}
} public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 64 * 1024;
public byte[] buffer = new byte[BufferSize];
public int isOnLine;//2表示在线,1,0表示不在线;
} private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
Socket closesocket = (Socket)state.workSocket;
string data = "GONE|" + Dns.GetHostAddresses(Dns.GetHostName())[0].ToString();
byte[] byteData = System.Text.Encoding.BigEndianUnicode.GetBytes(data);
closesocket.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), closesocket);
closesocket.Shutdown(SocketShutdown.Both);
closesocket.Close();
}
catch { }
}
}
}
我想问一下。如果客户端程序是一直运行的,服务器端的是不定时被打开的。我的服务器端程序可不可以这样做:服务器端程序启动后,由服务器向客户端发个字符串,服务器接收,并这个字符串在发给服务器,服务器判断有没有受到客户端发来的消息判断客户端是否在线。用个timer控制定时发消息给客户端,以保证实时的现实在线的客户端。不知道我这样想的合适吗?
思路上就错误了。始终运行着的那一端,才适合做Socket服务端。会被反复打开、关闭的那一端,才适合做Socket客户端。业务意义上的服务端和客户端,不一定非得对应Socket的服务端和客户端。你这个问题改用上述思路考虑一下,不就非常简单了吗?服务端启动后,启动Socket客户端,尝试连接Socket服务端(即业务上的客户端),连接成功后,Socket服务端在该连接上发送身份标识数据过去,不就完成业务登录了吗?
请问,如果业务上的客户端有多个也是由他了充当socket服务器吗?
2、“远程主机强迫关闭了一个现有的链接” 说明创建的Socket链接没有正确的关闭