前言

项目中要实现一个简单的socket服务器端,采用了TcpListener这个类。除了基本的功能之外,有几处需要注意的点。

  1. 要能同时接收多个客户端的连接,当然,不需要几千个那么多。
  2. 要能探测到客户端的断开。
  3. 要能关闭服务器端的监听。

这几个点之间,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服务器端的更多相关文章

  1. C# Socket服务器端如何判断客户端断开

    使用Socket类中的Poll方法,就可以. Socket client //假如已经创建好了,连接到服务器端得Socket的客户端对象. 我们只要client.Poll(10,SelectMode. ...

  2. C# Socket服务器端如何判断客户端断开求解

    Socket client //假如已经创建好了,连接到服务器端得Socket的客户端对象. 我们只要client.Poll(10,SelectMode.SelectRead)判断就行了.只要返回Tr ...

  3. linux下一对多socket服务器端多线程泄露问题

    线程创建多了,没有释放.导致内存泄露... int main() { int len; int on=1; // pMachList = CreateEmptyLinklist(); DataBase ...

  4. Socket编程——客户端,服务器端的读写操作

    URL网络编程,最大的特征就是一对一的响应! 1:客户端“写”,服务器端用于“读” package coreBookSocket2; import java.io.InputStreamReader; ...

  5. 【socket】一分钟理清 socket udpsocket tcpsocket tcplistener TCPClient和 UDPClient

    socket 套接字接口是各种语言tcp udp的网络操作的基础. 直接用socket 对象开发 可以选择 udpsocket  或者 tcpsocket ,两者在使用上仅一些方法和参数不同,所有的底 ...

  6. Python socket 客户端和服务器端

    connection, address = socket.accept() 调 用accept方法时,socket会时入“waiting”状态.客户请求连接时,方法建立连接并返回服务器.accept方 ...

  7. php socket客户端及服务器端应用实例

    经常有朋友会对php的socket应用充满疑惑,本文就以实例代码作一讲解,希望能对初学php的朋友起到一点帮助作用 具体代码如下: 1.服务器端代码: <?php class SocketSer ...

  8. Socket 进行发送

    最灵活的通信方式还是Socket ,TcpClient和Tcplistener只是对Socket进行了一些包装,从而使他们使用起来更简单一些 给出同步的服务器端 static void Main(st ...

  9. (45)C#网络3 socket

    一.TCP传输 using System.Net.Sockets; 1.最基本客户端连服务器 服务端运行后一直处于监听状态,客户端每启动一次服务端就接收一次连接并打印客户端的ip地址和端口号.(服务端 ...

随机推荐

  1. Python3 学习第九弹: 模块学习二之文件管理模块

    os模块 提供访问操作系统的接口 1> name 获得当前操作系统 其中 'nt' 是 windows 'posix' 是 linux 2> environ 获得当前系统的环境变量的字典, ...

  2. 最全的PHP常用函数大全

    PHP的一些常用函数 quotemeta() 函数在字符串中某些预定义的字符前添加反斜杠. quoted_printable_decode() 函数对经过 quoted-printable 编码后的字 ...

  3. RIA技术

    Rich Internet Application(富互联网应用程序,简称RIA),一种全新的Web应用程序架构,它结合了桌面软件良好的用户体验和web应用程序易部署的优点,很快获得了企业的青睐. 近 ...

  4. POJ 2828 (线段树 单点更新) Buy Tickets

    倒着插,倒着插,这道题是倒着插! 想一下如果 Posi 里面有若干个0,那么排在最前面的一定是最后一个0. 从后往前看,对于第i个数,就应该插在第Posi + 1个空位上,所以用线段树来维护区间空位的 ...

  5. HDU 2122 HDU Today【Floyd】

    题意:给出n条路,起点和终点,问最短距离 用map处理一下地名,再用floyd 可是不懂的是:为什么INF定义成0x7fffffff就输出一堆奇怪的东西,改成100000000就可以了 #includ ...

  6. Codeforces 475 B Strongly Connected City【DFS】

    题意:给出n行m列的十字路口,<代表从东向西,>从西向东,v从北向南,^从南向北,问在任意一个十字路口是否都能走到其他任意的十字路口 四个方向搜,搜完之后,判断每个点能够访问的点的数目是否 ...

  7. C++获取进程号及窗口

    #include <TlHelp32.h> //根据进程名获取进程ID BOOL GetPidByProcessName(TCHAR *pProcess, DWORD*dwPid) { H ...

  8. 移植linux(1)

    硬件环境:TQ2440   软件环境:linux-2.6.30.4 下载源码:ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.30.4.tar ...

  9. 09day1

    词编码 模拟 [问题描述] 一个发送机可以通过一条隧道发送一些以二进制代码组成的单词.在其尽头的接受机可以使用特殊技术恢复到最初的单词.每个单词最初都由0和1组成.所有的单词最初长度都为n(4< ...

  10. 【转】Qt数据库总结

    转自:http://blog.chinaunix.net/uid-25201977-id-3014100.html #include <QtSql>QT += sql QSqlDataba ...