1.前言
这两天在公司刚入职没得电脑,师傅叫我用tcp/ip编写一个小的聊天Demo。刚好这两天才看设计模式,就寻思着将设计模式里面学的的东西应用到这个小Demo中。考虑到后期代码的界面的复用,这里用的是Build模式,Builder模式主要用于“分步骤构建一个复杂的对象”。在这其中“分步骤”是一个稳定算法,也就是程序的主线,而负责对象的各个部分则经常变化。变化点在哪里,封装哪里,Builder模式主要在与应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步骤构建算法”的需求变动。代码链接。
2.服务端
不多bb,这几上代码。先创建一个抽象类,然后罗列出主要的方法。感觉这利用接口也可以实现出不错的效果。
public abstract class Server
{
public delegate void EventReceiveMessage(string message);
/// <summary>
/// 开始服务
/// </summary>
/// <returns></returns>
public abstract bool StartService();
/// <summary>
/// 停止服务
/// </summary>
/// <returns></returns>
public abstract bool EndService();
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
public abstract void SendMessage(string message);
/// <summary>
/// 连接状态
/// </summary>
public abstract bool ConnectState { get;}
/// <summary>
/// 数据接收事件
/// </summary>
public abstract event EventReceiveMessage OnReceiveMessage;
}
然后就是,这里使用Task进行后台线程监视数据变化,不过好像Task不适合这种长时间监测的任务,用线程池可能会好一点。
public class TcpConnectionServer : Server
{
private bool StartServiceBool = false;
private Socket sendreceiveSocket;
TcpListener server;
/// <summary>
/// 获取一个bool量,判断是否连接,这个值是根据Socket的连接状态来判定的
/// </summary>
public override bool ConnectState { get => (sendreceiveSocket!=null)?sendreceiveSocket.Connected:false; }
public override event EventReceiveMessage OnReceiveMessage;
public override bool EndService()
{
//先将StartServiceBool置为false
StartServiceBool = false;
sendreceiveSocket.Shutdown(SocketShutdown.Send);
server.Stop();
OnReceiveMessage("服务已关闭");
return true;
}
public override void SendMessage(string message)
{
byte[] res;
res = System.Text.Encoding.Default.GetBytes(message);
sendreceiveSocket.Send(res);//发送
//sendSocket.Shutdown(SocketShutdown.Send);
}
public override bool StartService()
{
IPAddress ipListener = new IPAddress(new byte[] { 127, 1, 1, 1 });
server = new TcpListener(ipListener, 8005);
server.Start();//服务端启动侦听
if(null!=OnReceiveMessage)
{
//防止其它线程操作事件
EventReceiveMessage TempOnReceiveMessage = OnReceiveMessage;
OnReceiveMessage("服务端启动成功");
}
sendreceiveSocket = server.AcceptSocket();
StartServiceBool = true;
Task task = Task.Factory.StartNew(() =>
{
//Socket s = sendreceiveSocket;
byte[] recByte = new byte[4096];
while (StartServiceBool)
{
try
{
if(sendreceiveSocket.Available>0)
{
int bytes = sendreceiveSocket.Receive(recByte, recByte.Length, 0);
//Encoding.Default.GetBytes("发送为空");
string recStr = Encoding.Default.GetString(recByte, 0, bytes);
OnReceiveMessage(recStr);
}
System.Threading.Thread.Sleep(100);
}
catch (Exception ex)
{
}
}
});
return true;
}
}
下面就是设计出的界面了
将Server封装起来,然后在界面中就可以直接调用了。客户端也是同样的道理,我将项目上传。
3.服务端
贴代码吧
namespace ConsoleClient
{
public abstract class Client
{
public delegate void EventReceiveMessage(string message);
/// <summary>
/// 连接服务器
/// </summary>
/// <returns></returns>
public abstract bool ConnectServer();
/// <summary>
/// 关闭连接
/// </summary>
/// <returns></returns>
public abstract bool DisConnect();
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
public abstract void SendMessage(string message);
/// <summary>
/// 连接状态
/// </summary>
public abstract bool ConnectState { get; }
/// <summary>
/// 数据接收事件
/// </summary>
public abstract event EventReceiveMessage OnReceiveMessage;
}
public class TcpConnectionClient : Client
{
public override bool ConnectState { get => (null!=Serverclient) ? Serverclient.Connected : false; }
public override event EventReceiveMessage OnReceiveMessage;
IPAddress IPClient;
TcpClient Serverclient;
NetworkStream SendReceiveStream;
bool StartServiceBool = false;
//this.reader = new StreamReader(this.stream);
//this.writer = new StreamWriter(this.stream);
public override bool ConnectServer()
{
//客户端
IPClient = IPAddress.Parse("127.1.1.1");
Serverclient = new TcpClient();
Serverclient.Connect(IPClient, 8005);//8005端口号,必须与服务端给定的端口号一致,否则天堂无门
SendReceiveStream = Serverclient.GetStream();
StartServiceBool = true;
Task task = Task.Factory.StartNew(() =>
{
byte[] buffer;
while (StartServiceBool)
{
try
{
if(Serverclient.Available > 0)
{
buffer = new byte[Serverclient.Available];
SendReceiveStream.Read(buffer, 0, Serverclient.Available);
string receoveStr = Encoding.Default.GetString(buffer);
OnReceiveMessage(receoveStr);
}
System.Threading.Thread.Sleep(100);
}
catch(Exception ex)
{
}
}
});
return true;
}
public override bool DisConnect()
{
StartServiceBool = false;
SendReceiveStream.Dispose();
Serverclient.Close();
Serverclient = null;
return true;
}
public override void SendMessage(string message)
{
byte[] res;
res = System.Text.Encoding.Default.GetBytes(message);
SendReceiveStream.Write(res,0,res.Length);
}
}
}
4.小结
TCP/IP还是很复杂的,这次写的很多方面不好,后面在慢慢研究。