应用TcpListener实现的socket服务器端
2024-09-20 22:05:32
前言
项目中要实现一个简单的socket服务器端,采用了TcpListener这个类。除了基本的功能之外,有几处需要注意的点。
- 要能同时接收多个客户端的连接,当然,不需要几千个那么多。
- 要能探测到客户端的断开。
- 要能关闭服务器端的监听。
这几个点之间,2和3我没有找到很好的方法,是通过捕获异常的方法解决的。
重点功能
要能同时接收多个客户端的连接
MSDN上面的代码例子是连接一个客户端的情况,我需要可以连接多个客户端,采用了多线程的方式,即连接一个客户端之后,把处理客户端消息的部分用一个线程处理,这样可以继续新的监听,核心代码如下:
private void ThreadListen()
{
while (this.StatusOn)
{
try
{
TcpClient client = this.serverListener.AcceptTcpClient();
this.clientList.Add(client);
this.ShowMsg(string.Format("客户端连接成功! ip = {0} port = {1}", ((IPEndPoint)client.Client.RemoteEndPoint).Address, ((IPEndPoint)client.Client.RemoteEndPoint).Port));
Thread t1 = new Thread(() => ThreadHandleMsg(client));
t1.Start();
}
catch (Exception ex)
{
Log.Error("", ex);
}
}
}
要能探测到客户端的断开
在如下代码之处,while循环的条件会阻塞掉,等待客户端的输入(i = stream.Read(bytes, 0, bytes.Length)) != 0
,这个不知道如何判断客户端断开,所以用了try catch比较low的办法。
Byte[] bytes = new Byte[1024];
String data = null;
NetworkStream stream = client.GetStream();
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
if (client == null || !client.Connected)
{
break;
}
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
this.ShowMsg(string.Format("收到消息: {0}", data));
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
stream.Write(msg, 0, msg.Length);
this.ShowMsg(string.Format("返回消息: {0}", data));
}
要能关闭服务器端的监听
另外也没有发现如何关闭服务器端的监听,我看了一下stackoverflow,也没发现特别好的办法。代码如下:
public void Close()
{
this.StatusOn = false;
foreach (var client in this.clientList)
{
if (client != null && client.Connected)
{
client.Close();
}
}
this.clientList.Clear();
this.serverListener.Server.Close();
this.serverListener.Stop();
this.ShowMsg("停止监视,关闭连接");
}
全部代码
using log4net;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
namespace srtc_attools.Bll
{
public class TcpServer
{
private static TcpServer inst;
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private List<TcpClient> clientList;
private TcpListener serverListener;
public Action<string> ShowMsg { get; set; }
public bool StatusOn { get; set; }
private TcpServer() { }
public static TcpServer GetInst()
{
if (inst == null)
{
inst = new TcpServer();
}
return inst;
}
private Thread threadListen;
public void Open(string ip, int port)
{
this.clientList = new List<TcpClient>();
this.StatusOn = true;
this.ShowMsg("开始监视,等待连接");
this.serverListener = new TcpListener(IPAddress.Parse(ip), port);
this.serverListener.Start();
threadListen = new Thread(() => ThreadListen());
threadListen.Start();
}
private void ThreadListen()
{
while (this.StatusOn)
{
try
{
TcpClient client = this.serverListener.AcceptTcpClient();
this.clientList.Add(client);
this.ShowMsg(string.Format("客户端连接成功! ip = {0} port = {1}", ((IPEndPoint)client.Client.RemoteEndPoint).Address, ((IPEndPoint)client.Client.RemoteEndPoint).Port));
Thread t1 = new Thread(() => ThreadHandleMsg(client));
t1.Start();
}
catch (Exception ex)
{
Log.Error("", ex);
}
}
}
private void ThreadHandleMsg(TcpClient client)
{
if (client.Connected)
{
try
{
Byte[] bytes = new Byte[1024];
String data = null;
NetworkStream stream = client.GetStream();
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
if (client == null || !client.Connected)
{
break;
}
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
this.ShowMsg(string.Format("收到消息: {0}", data));
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
stream.Write(msg, 0, msg.Length);
this.ShowMsg(string.Format("返回消息: {0}", data));
}
}
catch (Exception ex)
{
Log.Error("客户端发生错误\r\n", ex);
if(this.clientList.Contains(client))
{
this.clientList.Remove(client);
this.ShowMsg(string.Format("客户端断开连接! ip = {0} port = {1}", ((IPEndPoint)client.Client.RemoteEndPoint).Address, ((IPEndPoint)client.Client.RemoteEndPoint).Port));
}
}
}
}
public void Close()
{
this.StatusOn = false;
foreach (var client in this.clientList)
{
if (client != null && client.Connected)
{
client.Close();
}
}
this.clientList.Clear();
this.serverListener.Server.Close();
this.serverListener.Stop();
this.ShowMsg("停止监视,关闭连接");
}
}
}
最新文章
- 模拟AngularJS之依赖注入
- (原) 2.3 Curator使用
- Git版本控制常用命令整理
- web前端攻击详解
- npm中package.json详解
- jquery-validation 使用
- oc 正则图片<;img />; 标签
- ovs 实用案例
- break在switch中的使用例子
- GetStdHandle 函数--获取标准设备的句柄
- MySQL &#183; 引擎特性 &#183; InnoDB 数据页解析
- 学会分析YUV数据
- Django--CRM--modelformset的用法
- Asp.net 子域共享cookie
- XML中DTD,XSD的区别与应用
- beego api 服务允许跨域访问,解决前端访问报Access-Control-Allow-Origin问题
- vue watch详细用法
- 整理一些好用的css, javascript资源网站等
- Hello World ! 第一篇随笔
- 5月25日-js操作DOM遍历子节点
热门文章
- CSS_简介/语法结构/长度单位/应用方式/标签的样式重置/表单样式重置
- (转载) jQuery 页面加载初始化的方法有3种
- POJ 2125 Destroying The Graph (二分图最小点权覆盖集+输出最小割方案)
- 用canvas实现图片滤镜效果详解之视频效果
- Cython: 快速入门
- webpack的学习
- RequireJS入门指导 (转)
- js/ajax跨越访问-jsonp的原理和实例(javascript和jquery实现代码)
- Nginx实现多个站点使用一个端口(配置Nginx的虚拟主机)
- input框内默认文字点击消失