我大概看了一下UDPClient和TCPClient的类,有些想不明白,望大家指教:
send方法好说,不过receive方法有些迷惑,它是同步的,也就是说我启动receive方法后,直到等到有数据了,才能接收到,才能再做别的事情。那我能想到的一般的解决方案是开一个线程,反复轮询接收数据,另一个线程是用来发送数据的。一般的聊天软件是这么设计的吗?
谢谢指教。
send方法好说,不过receive方法有些迷惑,它是同步的,也就是说我启动receive方法后,直到等到有数据了,才能接收到,才能再做别的事情。那我能想到的一般的解决方案是开一个线程,反复轮询接收数据,另一个线程是用来发送数据的。一般的聊天软件是这么设计的吗?
谢谢指教。
这里我能想象的代码模式是,无限循环这个BeginReceive方法,作为接收数据用(类似于监听),至于Send方法,无所谓在什么时候,与接收是无关的。不知道我的理解对吗?
private void BeginService_Click(object sender, EventArgs e) {
try {
this.btnBegin.Enabled = false;
Socket listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listen.Bind(server_ip);
listen.Listen(LISTEN_NUM);
listen.BeginAccept(new AsyncCallback(OnConnectRequest), listen);
} catch (Exception) {
return;
}
} //开始侦听
public void OnConnectRequest(IAsyncResult ar) {
Socket listener = ar.AsyncState as Socket;
client = listener.EndAccept(ar); client.BeginReceive(msgBuff, 0, msgBuff.Length, SocketFlags.None, new AsyncCallback(OnRecievedData), client);
listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
} //接收数据
public void OnRecievedData(IAsyncResult ar) {
Socket listener = ar.AsyncState as Socket;
try {
int nBytesRec = listener.EndReceive(ar); if (nBytesRec > 0) {
//byte ==> string
string sRecieved = Encoding.Unicode.GetString(msgBuff, 0, nBytesRec); //处理来自客户端的消息
ProcessMessage(listener, sRecieved); //注册消息回调函数
SetupRecieveCallback(listener); //listener.Send(Encoding.Unicode.GetBytes(string.Format("Begin|kkun|kkun|{0}", user_list.Count <= 1)));
} else {
this.Invoke(new Action<IPEndPoint>(Tstring_User_Remove), listener.RemoteEndPoint);
this.Invoke(new Action<string>(Tstring_Info), string.Format("disconnect from server {0}", listener.RemoteEndPoint));
listener.Shutdown(SocketShutdown.Both);
listener.Close();
//continue;
}
} catch(Exception exp) {
this.Invoke(new Action<IPEndPoint>(Tstring_User_Remove), listener.RemoteEndPoint);
this.Invoke(new Action<string>(Tstring_Info), string.Format("disconnect from server {0}", listener.RemoteEndPoint));
this.Invoke(new Action<string>(Tstring_Info), string.Format("disconnect from server {0}", exp.Message));
listener.Shutdown(SocketShutdown.Both);
listener.Close();
}
} //处理接收到的消息
private void ProcessMessage(Socket listener, string sRecieved) {
//如果接收到的消息不为空的话
if (!string.IsNullOrEmpty(sRecieved)) {
//新客户端
UserInfo info = new UserInfo(); //定义消息格式
/*
* Command|UserName|UserPass|UserType
* Command|UserName|pbSource|pbTarget
*/
#region 处理命令
string[] str = sRecieved.Split('|');
string _Command = string.Empty;
if (str.Length >= 4) {
byte[] bSend = Encoding.Unicode.GetBytes(sRecieved);
switch (str[0]) {
case "Login":
#region 登录
//用户名
if (!string.IsNullOrEmpty(str[1])) {
info.UserName = str[1];
}
//密码
if (!string.IsNullOrEmpty(str[2])) {
info.UserPass = str[2];
}
//玩家类型,如红方,黑方
if (!string.IsNullOrEmpty(str[3])) {
info.UserType = str[3];
}
//保存客户端连接
if (null == info.UserSocket) {
info.UserSocket = listener;
} //添加到用户列表中
if (!user_list.ContainsKey(info.UserName)) {
user_list.Add(info.UserName, info);
this.Invoke(new Action<IPEndPoint>(Tstring_User), listener.RemoteEndPoint);
} bSend = Encoding.Unicode.GetBytes(string.Format("Begin|kkun|kkun|{0}", user_list.Count));
//foreach (UserInfo item in user_list.Values) {
// if (item != null && item.UserName != str[1]) {
// item.UserSocket.Send(bSend);
// }
//}
client.Send(bSend); break;
#endregion
case "Step":
case "Eat":
case "Back":
case "ToFaild":
foreach (UserInfo item in user_list.Values) {
if (item != null && item.UserName != str[1]) {
item.UserSocket.Send(bSend);
}
}
break;
case "Begin":
bSend = Encoding.Unicode.GetBytes(string.Format("Begin|{0}|{0}|{1}", str[1], user_list.Count));
foreach (UserInfo item in user_list.Values) {
if (item != null && item.UserName != str[1]) {
item.UserSocket.Send(bSend);
}
}
break;
default:
break;
}
this.Invoke(new Action<string>(Tstring_Info), string.Format(" > {0}", sRecieved));
} else {
//未定义的命令
this.Invoke(new Action<string>(Tstring_Info), string.Format("Undefined Command:{0}", sRecieved)); byte[] bSend = Encoding.Unicode.GetBytes(sRecieved);
foreach (UserInfo item in user_list.Values) {
if (item != null && item.UserName != str[1]) {
item.UserSocket.Send(bSend);
}
}
}
#endregion }
} //注册消息接收回调
public void SetupRecieveCallback(Socket listener) {
try {
AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
listener.BeginReceive(msgBuff, 0, msgBuff.Length, SocketFlags.None, recieveData, listener);
} catch (Exception ex) {
this.Invoke(new Action<string>(Tstring_Info),ex.Message);
}
}
/// 登录
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MenuItem_Click_Login(object sender, RoutedEventArgs e) {
try {
client = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
client.Blocking = false;
client.BeginConnect(clientInfo.ServerIPEndPoint, new AsyncCallback(OnConnect), client);
} catch (Exception exp) {
throw exp;
}
} #region 网络连接类
//连接上服务器后,准备接收消息
public void OnConnect(IAsyncResult ar) {
System.Net.Sockets.Socket sock = (System.Net.Sockets.Socket)ar.AsyncState;
try {
if (sock.Connected) {
//连接上服务器后,发送登录消息
string _Command = string.Format("Login|{0}|{1}|{2}", clientInfo.UserName, clientInfo.UserName, clientInfo.UserName);
byte[] _bCommand = Encoding.Unicode.GetBytes(_Command);
client.Send(_bCommand); AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
sock.BeginReceive(msgBuff, 0, msgBuff.Length, System.Net.Sockets.SocketFlags.None, recieveData, sock);
}
} catch (Exception ex) {
throw ex;
}
} //接收消息
public void OnRecievedData(IAsyncResult ar) {
System.Net.Sockets.Socket sock = (System.Net.Sockets.Socket)ar.AsyncState;
try {
int nBytesRec = sock.EndReceive(ar);
if (nBytesRec > 0) {
string sRecieved = Encoding.Unicode.GetString(msgBuff, 0, nBytesRec);
ProcessMessage(sock, sRecieved);
SetupRecieveCallback(sock);
} else {
sock.Shutdown(System.Net.Sockets.SocketShutdown.Both);
sock.Close();
}
} catch (Exception exp) {
sock.Shutdown(System.Net.Sockets.SocketShutdown.Both);
sock.Close();
throw exp;
}
} //注册消息接收回调函数
public void SetupRecieveCallback(System.Net.Sockets.Socket sock) {
try {
AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
sock.BeginReceive(msgBuff, 0, msgBuff.Length, System.Net.Sockets.SocketFlags.None, recieveData, sock);
} catch (Exception ex) {
MessageBox.Show(ex.Message);
this.Close();
}
} //处理接收到的消息
private void ProcessMessage(System.Net.Sockets.Socket listener, string sRecieved) {
//如果接收到的消息不为空的话
if (!string.IsNullOrEmpty(sRecieved)) {
#region 处理命令
string[] str = sRecieved.Split('|');
string _Command = string.Empty;
ChessDetail pbSource, pbTarget;
if (str.Length >= 4) {
switch (str[0].ToLower()) {
case "login":
this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new InitializeControlsDelegate(this.InitializeControls), int.Parse(str[3]));
break;
case "step":
pbSource = list[-int.Parse(str[2])];
pbTarget = list[-int.Parse(str[3])];
this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Tstring_Step_Delegate(this.Tstring_Step_Server), pbSource, pbTarget);
break;
case "eat":
pbSource = list[-int.Parse(str[2])];
pbTarget = list[-int.Parse(str[3])];
this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Tstring_Eat_Delegate(this.Tstring_Eat_Server), pbSource, pbTarget);
break;
case "back":
case "tofaild":
case "begin":
this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new InitializeControlsDelegate(this.InitializeControls), int.Parse(str[3]));
break;
default:
break;
}
}
#endregion
}
}
#endregion
里面网络编程中有我搜集的Socket开发的很多实例,也有我封装的简化的Socket的两个类
那两个类是用在pda于pc无线通信的,所以只取最简化方法。