凯发k8官方网
收集整理的这篇文章主要介绍了
[c#]手把手教你打造socket的tcp通讯连接(一)
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
本文章将讲解基于tcp连接的socket通讯,使用socket异步功能,并且无粘包现象,通过事件驱动使用。
在编写socket代码之前,我们得要定义一下socket的基本功能。
作为一个tcp连接,不论是客户端还是服务器端,它都得有以下接口:
public interface isocket
{/// /// 获取是否已连接。/// bool isconnected {
get; }/// /// 发送数据。/// /// 要发送的数据。void send(
byte[] data);/// /// 异步发送数据。/// /// 要发送的数据。void sendasync(
byte[] data);/// /// 断开连接。/// void disconnect();/// /// 异步断开连接。/// void disconnectasync(); /// /// 断开完成时引发事件。/// event eventhandler
disconnectcompleted;/// /// 接收完成时引发事件。/// event eventhandler receivecompleted;/// /// 发送完成时引发事件。/// event eventhandler sendcompleted;
} 用到的事件参数socketeventargs。
///
/// socket事件参数
///
public class socketeventargs : eventargs
{/// /// 实例化socket事件参数/// /// 相关socket/// 操作类型public socketeventargs(isocket socket, socketasyncoperation operation){if (socket == null)throw new argumentnullexception("socket");socket = socket;operation = operation;}/// /// 获取或设置事件相关数据。/// public byte[] data { get; set; }/// /// 获取数据长度。/// public int datalength { get { return data == null ? 0 : data.length; } }/// /// 获取事件相关socket/// public isocket socket { get; private set; }/// /// 获取事件操作类型。/// public socketasyncoperation operation { get; private set; }
} 因为作为客户端只管收发,比较简单,所以这里从客户端开始做起。
定义类tcpclient继承接口isocket和idisposable
///
/// tcp客户端
///
public class tcpclient : isocket, idisposable
{/// /// 获取是否已连接。/// public bool isconnected { get; }/// /// 发送数据。/// /// 要发送的数据。public void send(byte[] data){}/// /// 异步发送数据。/// /// 要发送的数据。public void sendasync(byte[] data){}/// /// 断开连接。/// public void disconnect(){}/// /// 异步断开连接。/// public void disconnectasync(){} /// /// 断开完成时引发事件。/// public event eventhandler disconnectcompleted;/// /// 接收完成时引发事件。/// public event eventhandler receivecompleted;/// /// 发送完成时引发事件。/// public event eventhandler sendcompleted;/// /// 释放资源。/// public void dispose(){}
} 并在此之上,增加以下方法
/// /// 连接至服务器。/// /// 服务器终结点。public void connect(ipendpoint endpoint){}/// /// 异步连接至服务器。/// /// public void connectasync(ipendpoint endpoint){}
下面我们开始编写构造函数,实例化一个socket并保存到私有变量里。
把isconnected指向socket.connected。
private socket socket;
private stream stream;
/// /// 实例化tcp客户端。/// public tcpclient(){socket = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp);}/// /// 获取是否已连接。/// public bool isconnected { get { return socket.connected; } } 因为接下来我们开始编写socket的异步功能,所以在此之前,我们要做一个状态类,用来保存异步状态。
internal class socketasyncstate
{/// /// 是否完成。/// public bool completed { get; set; }/// /// 数据/// public byte[] data { get; set; }
/// /// 是否异步/// public bool isasync { get; set; }
} 下面我们开始编写tcp连接功能。
/// /// 连接至服务器。/// /// 服务器终结点。public void connect(ipendpoint endpoint){//判断是否已连接if (isconnected)throw new invalidoperationexception("已连接至服务器。");if (endpoint == null)throw new argumentnullexception("endpoint");//锁定自己,避免多线程同时操作lock (this){socketasyncstate state = new socketasyncstate();//socket异步连接
socket.beginconnect(endpoint, endconnect, state).asyncwaithandle.waitone();//等待异步全部处理完成while (!state.completed) { }}}/// /// 异步连接至服务器。/// /// public void connectasync(ipendpoint endpoint){//判断是否已连接if (isconnected)throw new invalidoperationexception("已连接至服务器。");if (endpoint == null)throw new argumentnullexception("endpoint");//锁定自己,避免多线程同时操作lock (this){socketasyncstate state = new socketasyncstate();//设置状态为异步state.isasync = true;//socket异步连接
socket.beginconnect(endpoint, endconnect, state);}}private void endconnect(iasyncresult result){socketasyncstate state = (socketasyncstate)result.asyncstate;try{socket.endconnect(result);}catch{//出现异常,连接失败。state.completed = true;//判断是否为异步,异步则引发事件if (state.isasync && connectcompleted != null)connectcompleted(this, new socketeventargs(this, socketasyncoperation.connect));return;}//连接成功。//创建socket网络流stream = new networkstream(socket);//连接完成state.completed = true;if (state.isasync && connectcompleted != null){connectcompleted(this, new socketeventargs(this, socketasyncoperation.connect));}//开始接收数据
handler.beginreceive(stream, endreceive, state);}
///
/// 连接完成时引发事件。
///
public event eventhandler connectcompleted; 以上为连接服务器的代码,endconnect中最后的handler为一个处理io收发的类,这留到后面再说。
接下来我们开始做断开服务器的方法。
/// /// 断开与服务器的连接。/// public void disconnect(){//判断是否已连接if (!isconnected)throw new invalidoperationexception("未连接至服务器。");lock (this){//socket异步断开并等待完成socket.begindisconnect(true, enddisconnect, true).asyncwaithandle.waitone();}}/// /// 异步断开与服务器的连接。/// public void disconnectasync(){//判断是否已连接if (!isconnected)throw new invalidoperationexception("未连接至服务器。");lock (this){//socket异步断开socket.begindisconnect(true, enddisconnect, false);}}private void enddisconnect(iasyncresult result){try{socket.enddisconnect(result);}catch{}//是否同步bool sync = (bool)result.asyncstate;if (!sync && disconnectcompleted!=null){disconnectcompleted(this, new socketeventargs(this, socketasyncoperation.disconnect));}}//这是一个给收发异常准备的断开引发事件方法private void disconnected(bool raiseevent){if (raiseevent && disconnectcompleted != null)disconnectcompleted(this, new socketeventargs(this, socketasyncoperation.disconnect));} 至此,我们已经完成了客户端的连接于断开功能。
现在我们开始写客户端的发送接收功能。
对于socket的发送与接收,在大量数据吞吐的时候,容易造成粘包问题,要解决这个问题,我们先定义一个isockethandler接口。
该接口定义了socket的发送与接收。
public interface isockethandler
{/// /// 开始接收/// /// socket网络流/// 回调函数/// 自定义状态/// 异步结果iasyncresult beginreceive(stream stream, asynccallback callback, object state);/// /// 结束接收/// /// 异步结果/// 接收到的数据byte[] endreceive(iasyncresult asyncresult);/// /// 开始发送/// /// 要发送的数据/// 数据偏移/// 发送长度/// socket网络流/// 回调函数/// 自定义状态/// 异步结果iasyncresult beginsend(byte[] data, int offset, int count, stream stream, asynccallback callback, object state);/// /// 结束发送/// /// 异步结果/// 发送是否成功bool endsend(iasyncresult asyncresult);
} 在tcpclient中添加一个属性。
/// /// socket处理程序/// public isockethandler handler { get; set; } 这个isockethandler在上面的endconnect里有使用到beginreceive()。
而使用beginreceive的回调函数则是这个。
private void endreceive(iasyncresult result){socketasyncstate state = (socketasyncstate)result.asyncstate;//接收到的数据byte[] data = handler.endreceive(result);//如果数据长度为0,则断开socket连接if (data.length == 0){disconnected(true);return;}//再次开始接收数据
handler.beginreceive(stream, endreceive, state);//引发接收完成事件if (receivecompleted != null)receivecompleted(this, new socketeventargs(this, socketasyncoperation.receive) { data = data });} 有了这个回调函数,我们的客户端就能持续的接收数据。
现在剩下发送数据的功能要完成。
/// /// 发送数据。/// /// 要发送的数据。public void send(byte[] data){//是否已连接if (!isconnected)throw new socketexception(10057);//发送的数据不能为nullif (data == null)throw new argumentnullexception("data");//发送的数据长度不能为0if (data.length == 0)throw new argumentexception("data的长度不能为0");//设置异步状态socketasyncstate state = new socketasyncstate();state.isasync = false;state.data = data;try{//开始发送数据handler.beginsend(data, 0, data.length, stream, endsend, state).asyncwaithandle.waitone();}catch{//出现异常则断开socket连接disconnected(true);}}/// /// 异步发送数据。/// /// 要发送的数据。public void sendasync(byte[] data){//是否已连接if (!isconnected)throw new socketexception(10057);//发送的数据不能为nullif (data == null)throw new argumentnullexception("data");//发送的数据长度不能为0if (data.length == 0)throw new argumentexception("data的长度不能为0");//设置异步状态socketasyncstate state = new socketasyncstate();state.isasync = true;state.data = data;try{//开始发送数据并等待完成handler.beginsend(data, 0, data.length, stream, endsend, state);}catch{//出现异常则断开socket连接disconnected(true);}}private void endsend(iasyncresult result){socketasyncstate state = (socketasyncstate)result.asyncstate;//是否完成state.completed = handler.endsend(result);//没有完成则断开socket连接if (!state.completed)disconnected(true);//引发发送结束事件if (state.isasync && sendcompleted != null){sendcompleted(this, new socketeventargs(this, socketasyncoperation.send) { data = state.data });}} 至此,客户端的发送接收也完成了。
我们再写一下释放资源的方法。
/// /// 释放资源/// public void dispose(){lock (this){if (isconnected)socket.disconnect(false);socket.close();}} 整个客户端编写完成。
下一篇将讲解isockethandler的实现方法,用isockethandler来完成socket的io工作。
你可以在isockethandler中定义你自己的socket通讯协议。
原文地址:http://www.cnblogs.com/kation/archive/2013/03/06/2946761.html
转载于:https://www.cnblogs.com/kation/archive/2013/03/06/2946761.html
总结
以上是凯发k8官方网为你收集整理的[c#]手把手教你打造socket的tcp通讯连接(一)的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得凯发k8官方网网站内容还不错,欢迎将凯发k8官方网推荐给好友。