应用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地址和端口号.(服务端 ...
随机推荐
- listview android:cacheColorHint,android:listSelector属性作用
ListView是常用的显示控件,默认背景是和系统窗口一样的透明色,如果给ListView加上背景图片,或者背景颜色时,滚动时listView会黑掉, 原因是,滚动时,列表里面的view重绘时,用 ...
- easyui validatebox 验证集合
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <script src="easyui ...
- 适用于Firemonkey的Json解析对象XsuperObject使用方法介绍
XSuperObject是适用于FileMonkey平台的JSON解析组件,能够在Android,IOS,MACOS,WINDOWS等多个平台使用 点击下载 Sample JSON { "n ...
- HDU 3537 (博弈 翻硬币) Daizhenyang's Coin
可以参考Thomas S. Ferguson的<Game Theory>,网上的博客大多也是根据这个翻译过来的,第五章讲了很多关于翻硬币的博弈. 这种博弈属于Mock Turtles,它的 ...
- 51nod1431 快乐排队
神???.我们可以发现无论怎么交换ai+i都是不变的.那么这样就可以了 #include<cstdio> #include<cstring> #include<cctyp ...
- 16.Object-C--NSArray数组的排序
今天我来总结一下NSArray数组的排序方式. NSArray数组的排序有三种方式: 1.简单排序(sortedArrayUsingSelector:) 2.利用block语法(sortedArray ...
- 基于Html5的爱情主题网站–表白神器(第二版)
第二版在第一版的基础上增加了一个动态3D的白云效果背景,鼠标悬浮在页面上云朵会向屏幕Z轴方向运动,在第一人称视角看来向着云朵方向前进的,由此形成一个伪3D效果.有点绕,直接看demo就能理解了.3D白 ...
- ecshop 多语言切换
1.打开includes/init.php找到下面两行代码并删除 require(ROOT_PATH . 'languages/' . $_CFG['lang'] . '/common.php'); ...
- Android总结篇——Intent机制详解及示例总结
最近在进行android开发过程中,在将 Intent传递给调用的组件并完成组件的调用时遇到点困难,并且之前对Intent的学习也是一知半解,最近特意为此拿出一些时间,对Intent部分进行 ...
- C#格式化小数位的方法
C#格式化字符串还是很方便的,之前一直没用过,也就没有缘分了解 Double dValue = 95.12345; int iValue = 10000; string strValue = &quo ...