应用TcpListener实现的socket服务器端
前言
项目中要实现一个简单的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("停止监视,关闭连接");
}
}
}
应用TcpListener实现的socket服务器端的更多相关文章
- C# Socket服务器端如何判断客户端断开
使用Socket类中的Poll方法,就可以. Socket client //假如已经创建好了,连接到服务器端得Socket的客户端对象. 我们只要client.Poll(10,SelectMode. ...
- C# Socket服务器端如何判断客户端断开求解
Socket client //假如已经创建好了,连接到服务器端得Socket的客户端对象. 我们只要client.Poll(10,SelectMode.SelectRead)判断就行了.只要返回Tr ...
- linux下一对多socket服务器端多线程泄露问题
线程创建多了,没有释放.导致内存泄露... int main() { int len; int on=1; // pMachList = CreateEmptyLinklist(); DataBase ...
- Socket编程——客户端,服务器端的读写操作
URL网络编程,最大的特征就是一对一的响应! 1:客户端“写”,服务器端用于“读” package coreBookSocket2; import java.io.InputStreamReader; ...
- 【socket】一分钟理清 socket udpsocket tcpsocket tcplistener TCPClient和 UDPClient
socket 套接字接口是各种语言tcp udp的网络操作的基础. 直接用socket 对象开发 可以选择 udpsocket 或者 tcpsocket ,两者在使用上仅一些方法和参数不同,所有的底 ...
- Python socket 客户端和服务器端
connection, address = socket.accept() 调 用accept方法时,socket会时入“waiting”状态.客户请求连接时,方法建立连接并返回服务器.accept方 ...
- php socket客户端及服务器端应用实例
经常有朋友会对php的socket应用充满疑惑,本文就以实例代码作一讲解,希望能对初学php的朋友起到一点帮助作用 具体代码如下: 1.服务器端代码: <?php class SocketSer ...
- Socket 进行发送
最灵活的通信方式还是Socket ,TcpClient和Tcplistener只是对Socket进行了一些包装,从而使他们使用起来更简单一些 给出同步的服务器端 static void Main(st ...
- (45)C#网络3 socket
一.TCP传输 using System.Net.Sockets; 1.最基本客户端连服务器 服务端运行后一直处于监听状态,客户端每启动一次服务端就接收一次连接并打印客户端的ip地址和端口号.(服务端 ...
随机推荐
- visual studio 2015常用快捷键
常用快捷键 技巧 0.0 删除文件中的当前行: Home + Shife-End + Delete 技巧 1.1 避免意外复制一个空白行 工具->选项->文本编辑器->所有语言-&g ...
- UITableView中的(NSIndexPath *)indexPath
indexPath 用来指示当前单元格,它的row方法可以获得这个单元格的行号,section方法可以获得这个单元格所处的区域号
- mysql日期函数(转)
MySQL 获得当前日期时间 函数 获得当前日期+时间(date + time)函数:now() mysql> select now(); +---------------------+ | n ...
- 一行JS代码,解决DedeCMS TAG标签错误输入符号问题
在维护内容的时候, Tag标签输入经常要来回切换输入法, 只能通过','号分隔. 中文用户, 输入法出来的经常是全角的, 经常弄错, 增加了检查的工作量, 现在只要一句JS代码, 就自动替换所有 ...
- 【英语】Bingo口语笔记(46) - 不可能的表达
- Http和Https三次握手那些事
今天我总结了什么是HTTP三次握手,还有HTTPS握手的过程以及为什么HTTPS是安全的. 一:HTTP与TCP/IP区别? --->TPC/IP协议是传输层协议,主要解决数据如何在网络中传输 ...
- delete archivelog all 无法彻底删除归档日志?
最近在因归档日志暴增,使用delete archivelog all貌似无法清除所有的归档日志,到底是什么原因呢? 1.演示环境 SQL> select * from v$version whe ...
- Hbase常用命令
转:http://lib.csdn.net/article/hadoop/33499
- php-LAMP试题
ylbtech-doc:php-LAMP试题 LAMP试题 1.A,LAMP试题返回顶部 1.{PHP LAMP题目}变量$email的值是字符串 user@example.com ,以下哪项能把字符 ...
- java 地址记录
java在线API地址 http://docs.oracle.com/javase/7/docs/api/