TCP/IP异步通讯服务端实现方法

近期做了个TCP/IP异步通讯服务端实现方法,也是在网上胡乱搜索,然找了个自认为比较好的,然后封装一下,供后面自个使用,也供大家参考,如有不好的地方,欢迎指正,谢谢!

下面说一下这个方法里面的几个知识点:

1、托管

这个东西真心好用,虽然不知道具体怎么弄的,托管可以实现一个对象中的方法交由其他对象实现,而且可以同时触发多个方法,组件的触发函数就是由托管实现的,具体实现如下:

先声明一个托管的方法类型

public delegate void RecieveMsg(string IP_addr, int port, byte[] bytes, int length);

然后使用该托管类型声明一个方法

public event RecieveMsg OnRecieve;

最后直接在其他方法中调用该方法就可以了,如下

                if (bytesRead > 0)//接收到数据
                {
                    OnRecieve(client.IP_addr, client.Port, client.rec_buffer, bytesRead);//数据处理,由外部调用提供函数
                }

外部实现该方法时(注意里面有个小知识点,将string类型转换为char[] 类型方法:Encoding.UTF8.GetBytes())

socket_server.OnRecieve += new AsyncSocketServer.RecieveMsg(RecieveHandle);

        private void RecieveHandle(string IP_addr, int port, byte[] bytes, int length)
        {
            string strFileName = @"d:/data.txt";
            if (!File.Exists(strFileName))
            {
                File.CreateText(strFileName);
            }
            string temp;
            FileStream fs = new FileStream(strFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            temp = "\r\n" + IP_addr + " " + port.ToString() + ":";
            fs.Position = fs.Length;
            fs.Write(Encoding.UTF8.GetBytes(temp), 0, temp.Length);
            fs.Position = fs.Length;
            fs.Write(bytes, 0, length);
            fs.Close();
            socket_server.Send(IP_addr, port, bytes, length);
        }

2、刷新连接状态

使用异步通信不能实时获得各路client连接的状态,这里有个方法可以实现,当返回为真,则说明连接中断,该部分放在一个定时函数中定时执行:

                    if (((socket.Poll(1000, SelectMode.SelectRead) && (socket.Available == 0)) || !socket.Connected)) //连接中断
                    {

                    }

3、设置系统定时函数,注意在windows服务中一般是不允许出现窗体的,所以在函数中对form类的一些控件建议不要使用,虽然编译不会出错,但控件对应的方法却不会执行。

先声明一个定时器:

System.Timers.Timer updata_time;

初始化定时器:

            updata_time = new System.Timers.Timer(1000);//定时1s
            updata_time.Enabled = true;//使能定时器
            updata_time.AutoReset = true;//设置为循环执行
            updata_time.Elapsed += new System.Timers.ElapsedEventHandler(this.updata_time_Tick);

最后实现定时调用的函数 updata_time_Tick。

4、重载,本次使用了一个单独的类来封装客户端,为了便于集成管理,需要对一些方法重载,如Equals,特别是对ArrayList类,所有涉及到查找的方法都涉及到Equals方法,其重载实现如下:

        public override bool Equals(Object obj)
        {
            IP_Port IP_port = obj as IP_Port;//传入参数为 IP_Port
            if (IP_port != null)
            {
                if ((IP_port.IP_addr == this.IP_addr) && (IP_port.port == this.Port))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            Client client = obj as Client;//传入参数为Client
            if (client != null)
            {
                if ((client.IP_addr == this.IP_addr) && (client.Port == this.Port))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            return false;
        }

注意里面 IP_Port IP_port = obj as IP_Port 可以判断传入的参数是什么类型,这样可以根据不同的传入参数做不同的方法,增加灵活性。

其他的方法是用如下:

clients.Remove(clients[i]);
int index = clients.IndexOf(ip_port);

这个类的使用方法很简单:

AsyncSocketServer socket_server;
            socket_server.OnRecieve += new AsyncSocketServer.RecieveMsg(RecieveHandle);
            socket_server.OnSend += new AsyncSocketServer.SendMsg(SendBackHandle);
            socket_server.OnException += new AsyncSocketServer.ExceptionMsg(ExceptionHandle);

            socket_server.StartListen();

还有在结束时调用StopListen()

具体源文件如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;

namespace AsyncSocketServerApp
{
    class AsyncSocketServer
    {
        #region 公共成员
        public int port;//需要监听的本机端口号
        public delegate void RecieveMsg(string IP_addr, int port, byte[] bytes, int length);//接受数据后,需要外部函数来处理
        public event RecieveMsg OnRecieve;
        public delegate void SendMsg(string IP_addr, int port, int length);//发送数据完成后,需要外部函数来处理
        public event SendMsg OnSend;
        public delegate void ExceptionMsg(string IP_addr, int port, Exception e);//发生异常函数
        public event ExceptionMsg OnException;
        #endregion 

        #region 私有成员
        private Socket socket;
        private ArrayList clients;
        static private bool bListening = false;
        Thread thread;
        System.Timers.Timer updata_time;

        #endregion

        #region 公共方法
        public AsyncSocketServer()
        {
            port = 1234;//默认端口号
            SystemInit();
        }

        public AsyncSocketServer(int _port)
        {
            port = _port;//默认端口号
            SystemInit();
        }

        ~AsyncSocketServer()//析构函数
        {
            try
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
            }
            catch { }
        }

        public void StartListen()//开始监听
        {
            if (bListening == false)
            {
                thread = new Thread(new ThreadStart(this.SocketInit));
                bListening = true;
                thread.Start();
            }
        }

        public void StopListen()//停止监听
        {
            if (bListening == true)
            {
                try
                {
                    socket.Shutdown(SocketShutdown.Both);
                }
                catch { }
                socket.Close();
                thread.Abort();
                bListening = false;
            }
        }

        public int Send(string IP_addr, int port, byte[] bytes, int length)//发送数据到客户端
        {
            if (clients.Count == 0) return -1;
            IP_Port ip_port = new IP_Port(IP_addr, port);
            int index = clients.IndexOf(ip_port);
            if (index < 0) return -1;
            Client client = (Client)clients[index];
            client.socket.BeginSend(bytes, 0, length, 0, new AsyncCallback(SendCallback), client);
            return length;
        }

        public ArrayList GetClientList()//获取客户端列表
        {
            ArrayList client_list = new ArrayList();
            IP_Port ip_port;
            Monitor.Enter(clients);//获取对象锁防止在访问clients时updata_time_Tick线程修改 add by LC 2014.08.18 11:14
            try
            {
                if (clients.Count == 0) return null;
                foreach (Object obj in clients)
                {
                    Client client = (Client)obj;
                    ip_port = new IP_Port(client.IP_addr, client.Port);
                    client_list.Add(ip_port);
                }
            }
            finally { Monitor.Exit(clients); }//释放该对象,必须执行 add by LC 2014.08.18 11:15
            return client_list;
        }
        #endregion

        private void SystemInit()//form类的定时器改成System.Timers.Timer类 modfiy by LC 2014.08.14 16:51
        {
            clients = new ArrayList();
            updata_time = new System.Timers.Timer(1000);//定时1s
            updata_time.Enabled = true;//使能定时器
            updata_time.AutoReset = true;//设置为循环执行
            updata_time.Elapsed += new System.Timers.ElapsedEventHandler(this.updata_time_Tick);
        }
        private void SocketInit()
        {
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ip_end_point = new IPEndPoint(IPAddress.Any, port);
            socket.Bind(ip_end_point);
            socket.Listen(int.MaxValue);//开始监听,可连接数量设为最大
            socket.BeginAccept(new AsyncCallback(AcceptCallback), socket);
        }

        private void AcceptCallback(IAsyncResult ar)
        {
            try
            {
                Socket listener = (Socket)ar.AsyncState;
                Socket handler = listener.EndAccept(ar);
                EndPoint ip = handler.RemoteEndPoint;
                Client client = new Client();
                client.socket = handler;
                //IP_Port ip_port = new IP_Port((handler.RemoteEndPoint as IPEndPoint).Address.ToString() , (handler.RemoteEndPoint as IPEndPoint).Port);
                if (!clients.Contains(client))//判断原来有没有连接,若没有,则添加到客户端列表
                {
                    clients.Add(client);
                }
                handler.BeginReceive(client.rec_buffer, 0, Client.BufferSize, 0, new AsyncCallback(ReadCallback), client);
                listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);//继续侦听其他连接
            }
            catch { }
        }

        private void ReadCallback(IAsyncResult ar)
        {
            Client client = (Client)ar.AsyncState;
            try
            {
                Socket handler = client.socket;
                int bytesRead = handler.EndReceive(ar);
                if (bytesRead > 0)//接收到数据
                {
                    OnRecieve(client.IP_addr, client.Port, client.rec_buffer, bytesRead);//数据处理,由外部调用提供函数
                }
                handler.BeginReceive(client.rec_buffer, 0, Client.BufferSize, 0, new AsyncCallback(ReadCallback), client);
            }
            catch(Exception re)
            { OnException(client.IP_addr, client.Port, re); }
        }

        private void SendCallback(IAsyncResult ar)//发送成功后的回调函数
        {
            Client client = (Client)ar.AsyncState;
            try
            {
                int bytes_sent = client.socket.EndSend(ar);
                OnSend(client.IP_addr, client.Port, bytes_sent);//发送成功后返回
            }
            catch (Exception re)
            { OnException(client.IP_addr, client.Port, re); }
        }

        private void updata_time_Tick(object sender, EventArgs e)//1s执行一次
        {
            if (clients.Count == 0) return;
            Monitor.Enter(clients);// add by LC 2014.08.18 11:17
            try
            {
                for (int i = 0; i < clients.Count; i++)
                {
                    Socket socket = ((Client)clients[i]).socket;//指向错误 modfiy by LC 2014.08.14 16:58
                    if (((socket.Poll(1000, SelectMode.SelectRead) && (socket.Available == 0)) || !socket.Connected)) //连接中断
                    {
                        //socket.Shutdown(SocketShutdown.Both);
                        //socket.Close();
                        //MessageBox.Show((socket.RemoteEndPoint as IPEndPoint).Address.ToString() + ":" + (socket.RemoteEndPoint as IPEndPoint).Port.ToString() + "连接中断");
                        clients.Remove(clients[i]);
                    }
                }
            }
            catch (Exception re)
            { OnException("updata list ", 0, re); }
            Monitor.Exit(clients);// add by LC 2014.08.18 11:17
        }

    }

    public class IP_Port
    {
        public string IP_addr;
        public int port;

        public IP_Port(string e_IP, int e_port)
        {
            IP_addr = e_IP;
            port = e_port;
        }
    }

    public class Client
    {
        private int _port;//端口号
        private string _IP_addr;//IP号

        public Socket socket;
        public static int BufferSize = 1024;     // Receive buffer. 
        public byte[] rec_buffer = new byte[BufferSize];     // Received data string. 

        ~Client()
        {
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
        }

        public int Port//读取端口号
        {
            get
            {
                _port = (socket.RemoteEndPoint as IPEndPoint).Port;
                return _port;
            }
        }

        public string IP_addr
        {
            get
            {
                _IP_addr = (socket.RemoteEndPoint as IPEndPoint).Address.ToString();
                return _IP_addr;
            }
        }

        public override bool Equals(Object obj)
        {
            IP_Port IP_port = obj as IP_Port;//传入参数为 IP_Port
            if (IP_port != null)
            {
                if ((IP_port.IP_addr == this.IP_addr) && (IP_port.port == this.Port))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            Client client = obj as Client;//传入参数为Client
            if (client != null)
            {
                if ((client.IP_addr == this.IP_addr) && (client.Port == this.Port))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            return false;
        }
        public override int GetHashCode()
        {
            return Port;
        }
        public void RelaseTcpClient()//释放TcpClient资源
        {
            try
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
                socket.Close();
            }
            catch
            {

            }
        }
    }
}

TCP/IP异步通讯服务端实现方法

时间: 2024-08-06 21:09:41

TCP/IP异步通讯服务端实现方法的相关文章

异步tcp通信——APM.Core 服务端概述

为什么使用异步 异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池.就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理.异步操作执行时,会将操作丢给线程池中的某个工作线程来完成.当开始I/O操作的时候,异步会将工作线程还给线程池,这意味着获取网页的工作不会再占用任何CPU资源了.直到异步完成,即获取网页完毕,异步才会通过回调的方式通知线程池.可见,异步模式借助于线程池,极大地节约了CPU的资源. 注:DMA(Direct Memory Acce

TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q

TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q 一.TCP协议下的服务端并发 ''' 将不同的功能尽量拆分成不同的函数,拆分出来的功能可以被多个地方使用 TCP服务端实现并发 1.将连接循环和通信循环拆分成不同的函数 2.将通信循环做成多线程 ''' # 服务端 import socket from threading import Thread ''' 服务端 要有固定的IP和PORT 24小时不间断提供服务 能够支持并发 ''' server = sock

网络编程 UDP协议 TCP局域网客户端与服务端上传下载电影示例

UDP协议 (了解) 称之为数据包协议. 特点: 1) 不需要建立链接. 2) 不需要知道对方是否收到. 3) 数据不安全 4) 传输速度快 5)能支持并发 6) 不会粘包 7) 无需先启动服务端再启动客户端 优点: - 传输速度快 - 能支持并发 - 不会粘包 缺点: - 数据不安全, 容易丢失 应用场景: 早期的QQ聊天室. # server端 import socket # socket.SOCK_DGRAM ---> UPD协议 server = socket.socket(type=s

java网络编程TCP传输—流操作—服务端反馈与客户端接收

在读取完流后,服务端会向客户端返回一些数据,告诉客户端,已经写完了. 在这里和”流操作—拿到源后的写入动作“差不多,客户端同样以byte与Buffered两种缓冲读取作为例子,同时,.也是希望大家给补充. 1.利用OutputStream向客户端回写,客户端用byte作为缓冲接收 向客户端回写: 1 //获取socket输出流,将上传成功字样传给客户端 2 OutputStream out=s.getOutputStream(); 3 out.write("上传成功".getBytes

WCF 通过net tcp 协议 ,在服务端服务器和客户端服务器之间传输数据,注意配置事项

1. 特别注意  binding name="BindingBehaviorConfiguration" (名字可以随意取,但是必须要服务端和客户端保持一致) bindingConfiguration="BindingBehaviorConfiguration" 如何没有配置保持一致:出现:服务器已拒绝客户端凭据 如果没有配置:security mode="None", 出现的现象:服务器已拒绝客户端凭据 //----服务端配置实例: <?

Webservice客户端动态调用服务端功能方法

一.发布WebService服务 方式一:在服务端生成wsdl文件,下方客户端直接引用即可 优点:针对要发布的方法生成一个wsdl文件即可,无需多余配置. 缺点:每次服务端方法发生改变都需要重新生成相应的wsdl文件,不适合于功能需要经常变动的方法. 方式二: 二.Client调用服务端接口  1. 项目架构如下: 2.调用过程: 1)右键点击项目名称-->"NEW"-->"Other"-->输入WEB service client 如下 2)完成

Oracle客户端无法连接服务端解决方法及步骤

客户端无法连接服务端数据库,原因有网络,配置,文件访问权限,数据库服务是否已启动 等问题导致,一般排查的步骤如下:1.检查操作系统级别网络是否通畅 ping 192.168.10.1 2.检查数据库层网络是否通畅 tnsping myserverdb 3.检查监听状态是否正常 lsnrctl status listener 4.如果第二步不通,检查服务端监听配置是否正确 监听文件配置一般如下 # 监听名称 LISTENER= (DISCRIPTION = (ADDRESS=(PROTOCOL =

tcp/ip (网络通讯协议)

介绍 TCP: 传输控制协议, IP: 网际协议, TCP/IP: 供已连接互联网的计算机之间进行通信的通信协议 在tcp/ip内部 , 包含一系列处理数据通信的协议: tcp.udp.icmp.dhcp ip负责将每个包路由至它的目的地.(网络层) tcp用于应用程序之间的通信, 负责处理ip包.(传输层) RFC是tcp/ip协议的标准文档. tcp/ip, 又名: 网络通讯协议. 寻址 ip地址: 每个计算机必须有ip地址才能够接入互联网, 每个ip包必须有一个地址才能够发送到目的计算机.

利用socketserver实现异步多线程服务端简单聊天功能

废话不多说,直接上代码 程序组成 数据访问层:model-------chat_log.py(用于保存聊天记录及展示) ---user_info.py(用户登录信息表,验证通过才能聊天) 公共功能层:utility-------sqlhelper.py(用于处理查询及插入数据的操作) ---conf.py(用于保存数据库连接字符串) 主程序:server.py--------Socket服务端 client.py----------Socket客户端 server.py 1 #!/usr/bin