看到那么多人支持,我很感动,所以临时决定从今天开始讲述如何编写IM。
那么今天开始第一讲, Socket.
为什么上来就讲Socket呢?因为我觉得作为一个对于IM很感兴趣的人,应该瞬间提升对于网络编程的高度认知,只有这样才能快速的学到东西。
那么好了,开始实战!
Socket又分为异步套接字和同步套接字,我在项目中基本上都是用的同步(当然,您可以使用异步),然后自己New的线程,这样的话,我感觉有几点好处。
1. 对于线程拥有更加的认知度。
2. 启用了自己制作的线程池(ThreadPool <-这个我自己写了个)
那么先说线程,Socket监听一般是需要2个While--true的,这个也是通用写法,貌似很多学校也这样教?
那么下面进入代码时间,我先来粘贴出一段有问题的代码(服务端部分):
while (_IsListen) //<----监听标示
{
Listener.Start(); //一直监听
//尝试接受连接
this.socket = Listener.AcceptSocket(); //获得连接信息
//MessageBox.Show("有人连接了:Socket Port:" + this.socket.RemoteEndPoint.ToString());
//如果此套接字已经连接上
if (this.socket.Connected)
{
while(true)
{
//do sth
}
}
}
catch(Exception ex)
{
}
上面这段代码减去了没必要的部分,但是足足可以说明问题,上面这段代码运行是没有问题的,而且能监听指定端口。
不知道您看出问题了吗?
慢慢的,你就会发现,这段代码有问题了,而且有大问题,因为当我有1个用户上线并且成功与服务器连接后,再来一个用户上线,那么第一个
用户便不会再与服务器进行任何响应了,这是为什么呢?
呵呵 ,可能有人看出来了?服务器第一个While循环为了得到用户的SOCKET,当得到后,传递到第二个While,这样一来,就会一直在第二个While循环中
出不来了……而且整个窗体会卡住。
那么好,我们改下,比如现在把第二个While用多线程处理,看代码(服务端部分):
public void Lis_Port()
{
Listener = new TcpListener(Globle._OnLinePort); //默认上线端口:10000
try
{
Globle._isRuning = 1; //开启启动
this.Main_f.BeginInvoke(new Pt(Main_f.Update_TM_Run));
this.Main_f.BeginInvoke(new Pt(Main_f.Update_State));
while (_IsListen)
{
Listener.Start(); //一直监听
//尝试接受连接
this.socket = Listener.AcceptSocket(); //获得连接信息
//MessageBox.Show("有人连接了:Socket Port:" + this.socket.RemoteEndPoint.ToString());
//如果此套接字已经连接上
if (this.socket.Connected)
{
Thread thread = new Thread(new ThreadStart(this.Rev));
thread.Start();
}
}
}
catch(Exception ex)
{
Globle._isRuning = 0; //停止启动
this.Main_f.BeginInvoke(new Pt(Main_f.Update_State));
//MessageBox.Show("端口监听出现错误:" + ex.Message);
}
}
#endregion
#region 此方法用于监听用户命令
/*
* 此方法用于监听用户命令
*/
public void Rev()
{
while (_IsListen)
{
try
{
byte[] bb = new byte[512];
//如果此套接字已经连接上
if (this.socket.Connected)
{
Stream = new NetworkStream(this.socket); //获取用户流信息
Stream.Read(bb, 0, bb.Length); //读取内容
Stream.Flush(); //清空
//MessageBox.Show(Encoding.Default.GetString(bb));
this.Rev_Order = (Encoding.Default.GetString(bb)).Replace("/0", ""); //转换成字符串
String[] Orders_sp = this.Rev_Order.Split(new String[] { "$$" }, StringSplitOptions.RemoveEmptyEntries);
//如果得到的命令不是登录后的信息传递
if (Orders_sp.Length <= 1)
{
String[] Orders = this.Rev_Order.Split(new String[] { "|**|" }, StringSplitOptions.RemoveEmptyEntries);
if (Orders.Length <= 1)
{
String Ip = IPAddress.Parse(((IPEndPoint)this.socket.RemoteEndPoint).Address.ToString()).ToString();
Rev2Client_SendMessage Rev = new Rev2Client_SendMessage(Stream, this.Rev_Order, Ip);
}
catch (Exception ex)
{
MessageBox.Show("显示用户上线的时候出现错误:" + ex.Message);
}
}
//QQ注册
else
{
//do sth
}
else
{
//do sth
}
else
{
//MessageBox.Show("套接字已经断开了");
}
}
}
}
public MessageListener(Socket UserSocket)
{
}
public void Start()
{
Thraed thread = new Thread(new ThreadStart(this.INNER_LISTEN));
thread.Start();
}