110,529
社区成员
发帖
与我相关
我的任务
分享
public void Connect(string conIP, int conPort, DoServerBack ServerBackDeel, string strData)
{
//创建套接字
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
doServerBack = ServerBackDeel;
//开始连接到服务器
try
{
//连接指定服务器
client.Connect(conIP, conPort);
if (client.Connected)
{//连接成功
//向服务器发送服务请求
//因为传输时结束字符串可能被截为两段,所以结束符多发一次,以保证服务器收到结束符
//SendMessage("DATESTART" + strData + "DATEENDDATEEND");
SendMessage(strData);
//开始接收服务器返回结果
client.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
}
else
{//连接失败
client.Close();
}
}
catch (Exception ex)
{
client.Close();
//如果显示提示,那么在后台静默等待服务器开启时
//就会出现显示即程序暂停的情况
}
}
/// <summary>
/// 接收数据调用方法
/// </summary>
/// <param name="ar"></param>
private void ReceiveCallBack(IAsyncResult ar)
{
try
{
if (client.Connected)
{
byteSource.AddRange(receiveBuffer);//接收数据
//检查数据中是否有结尾标记
int REnd = client.EndReceive(ar);
string strReceiveData = Encoding.UTF8.GetString(receiveBuffer, 0, REnd);
if (!string.IsNullOrEmpty(strReceiveData))
{//如果字符串不为空
//检测结束符
int endloc = strReceiveData.IndexOf("DATEEND");
if (endloc > 0)
{//接收数据结束
ReciveData = Encoding.UTF8.GetString(byteSource.ToArray());
int start = ReciveData.IndexOf("DATESTART") + "DATESTART".Length;
int end = ReciveData.IndexOf("DATEEND");
ReciveData = ReciveData.Substring(start, end - start);
//实际使用中发现会出现数据传输错误,故加入哈希验证,减少错误数据读取率
string[] resultData = ReciveData.Split('\f');
if (Cls_WaterSocketMessage.GetHashValue(resultData[0]) == resultData[1])
{//哈希值字符串比较
doServerBack(resultData[0]);
}
else
{
doServerBack("FALSE");
}
timeoutObject.Set();//这里设置结果超时控制的阻塞
}
}
//this.HandleMessage(strReceiveData);
if (client.Connected)
{
client.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
}
}
}
catch (Exception ex)
{
//System.Windows.Forms.MessageBox.Show("ReceiveCallBack " + ex.Message);
}
}
public void SendMessage(Socket s, string ms)
{
if (!s.Poll(500, SelectMode.SelectRead))
{
s.Send(Encoding.UTF8.GetBytes(
"DATESTART" //报文开头
+ ms //报文内容
+ "\f" //报文与其哈希值的分隔符
+ Cls_WaterSocketMessage.GetHashValue(ms) //报文内容的哈希值
+ "DATEENDDATEEND"));
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace WaterClassLibrary
{
/// <summary>
/// Socket 客户端类
/// </summary>
public class Cls_SocketClient
{
/// <summary>
/// 连接服务器的Socket
/// </summary>
public Socket client;
/// <summary>
/// 接收到的数据
/// </summary>
//private string ReciveData;
private StringBuilder strBuilder = new StringBuilder();
/// <summary>
/// SOCKET 状态
/// </summary>
ManualResetEvent timeoutObject = new ManualResetEvent(false);//通知一个或多个正在等待的线程已发生事件
/// <summary>
/// 接收服务器发来的数据后执行的方法
/// </summary>
/// <param name="ServerBackBack">服务器返回的数据</param>
public delegate void DoServerBack(string ServerBackBack);
DoServerBack doServerBack;
/// <summary>
/// 获取或设置客户端等待获取服务器回应的最长时间(毫秒)
/// 默认30000(30秒)
/// </summary>
public int millisecondsTimeout = 30000;
/// <summary>
/// 接收数据缓存
/// </summary>
private byte[] receiveBuffer = new byte[1024];
/// <summary>
/// 用于存储接收的数据
/// </summary>
List<byte> byteSource = new List<byte>();
/// <summary>
/// 接收数据长度
/// </summary>
private int ReceiveDataLength;
#region 连接并接收数据
/// 连接时应当处理超时问题,否则可能在连接时过长时间等待
/// 最终造成连接失败,或是无反应假像。
/// <summary>
/// 连接到服务器
/// </summary>
/// <param name="conIP">连接IP</param>
/// <param name="conPort">连接端品</param>
/// <param name="ServerBackDeel"></param>
/// <param name="csmt"></param>
public void Connect(string conIP, int conPort, DoServerBack ServerBackDeel, Cls_WaterSocketMessage csmt)
{
//创建套接字
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
doServerBack = ServerBackDeel;
//开始连接到服务器
try
{
#region Old code,without timeout
//连接指定服务器
client.Connect(conIP, conPort);
if (client.Connected)
{//连接成功
//向服务器发送服务请求
string s = csmt.GetSendMessageString();
SendMessage(s);
//开始接收服务器返回结果
client.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
}
else
{//连接失败
client.Close();//释放资源
}
#endregion
}
catch (Exception ex)
{
client.Close();
//如果显示提示,那么在后台静默等待服务器开启时
//就会出现显示即程序暂停的情况
//System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
/// <summary>
/// 连接到服务器
/// </summary>
/// <param name="conIP">连接IP</param>
/// <param name="conPort">连接端口</param>
/// <param name="ServerBackDeel"></param>
/// <param name="strData"></param>
public void Connect(string conIP, int conPort, DoServerBack ServerBackDeel, string strData)
{
//创建套接字
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
doServerBack = ServerBackDeel;
//开始连接到服务器
try
{
//连接指定服务器
client.Connect(conIP, conPort);
if (client.Connected)
{//连接成功
//向服务器发送服务请求
SendMessage(strData);
//开始接收服务器返回结果
client.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
}
else
{//连接失败
client.Close();
}
}
catch (Exception ex)
{
client.Close();
//如果显示提示,那么在后台静默等待服务器开启时
//就会出现显示即程序暂停的情况
}
}
/// <summary>
/// 接收数据调用方法
/// </summary>
/// <param name="ar"></param>
private void ReceiveCallBack(IAsyncResult ar)
{
try
{
if (client.Connected)
{
int REnd = client.EndReceive(ar);
byte[] tmpbyte = new byte[REnd];
Array.Copy(receiveBuffer, 0, tmpbyte, 0, REnd);
byteSource.AddRange(tmpbyte);//接收数据
#region 使用长度来标记是否已接收结束
if (ReceiveDataLength <= 0
&& byteSource.Count >= 4)
{//还未计算接收长度,同时,接收到的长度已经大于或等于长度位长度
byte[] byteLengthg = new byte[4];
Array.Copy(byteSource.ToArray(), 0, byteLengthg, 0, 4);
ReceiveDataLength = Cls_WaterSocketMessage.byteArrayToInt(byteLengthg);//使转换方式与JAVA一致
}
if (byteSource.Count >= ReceiveDataLength + 4)
{//数据已全部接收到
if (doServerBack != null)
{//返回方法不为空
string data = Encoding.UTF8.GetString(byteSource.ToArray(), 4, ReceiveDataLength);
//实际使用中发现会出现数据传输错误,故加入哈希验证,减少错误数据读取率
int indexf = data.LastIndexOf('\f');
string resultData = data.Substring(0, indexf);
string hashData = data.Substring(indexf + 1, data.Length - indexf - 1);
if (Cls_WaterSocketMessage.GetHashValue(resultData) == hashData)
{//哈希值字符串比较
doServerBack(resultData);
}
else
{
doServerBack("FALSE");
}
}
timeoutObject.Set();//这里设置结果超时控制的阻塞
client.Close();//结束连接
return;
}
#endregion
if (client.Connected)
{
client.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
}
}
}
catch (Exception ex)
{
}
}
#endregion
/// <summary>
/// 断开连接
/// </summary>
public void DeConnect()
{
try
{
if (client != null)
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
}
catch (Exception ex)
{
string a = ex.Message;
}
}
/// <summary>
/// 修改为添加哈希验证
/// </summary>
/// <param name="sendmessage"></param>
private void SendMessage(string sendmessage)
{
byte[] sendData = Encoding.UTF8.GetBytes(sendmessage); //报文内容转 byte
byte[] hashcode = Encoding.UTF8.GetBytes("\f" + Cls_WaterSocketMessage.GetHashValue(sendmessage));//报文内容的哈希值
byte[] sendHead = Cls_WaterSocketMessage.intToByteArray(sendData.Length + hashcode.Length);//报文头,使转换方式与JAVA一致
if (client != null)
{
//发送报文长度,int 占4个byte
client.Send(sendHead); //发送报文头
client.Send(sendData); //发送报文信息
client.Send(hashcode); //发送信息哈希验证码
}
}
/// <summary>
/// 如果连接失败或是未返回就中断,则返回false
/// 成功连接返回true
/// 这里设置了最长等待判断时长为10000毫秒,即10秒,否则可能出现长时间等待
/// </summary>
/// <returns></returns>
public bool CheckConnect()
{
try
{
if (this.client == null)
{
return false;
}
else if (this.client.Connected == false)
{
DeConnect();
return false;
}
if (!timeoutObject.WaitOne(millisecondsTimeout,false))
{
DeConnect();
return false;
}
return true;
}
catch
{
return false;
}
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace WaterClassLibrary
{
/// <summary>
/// Socket 服务器端类
/// 客户端尽可能连接一次只能做一次发送
/// </summary>
public class Cls_SocketServer
{
private IPAddress ServerIP;
private int Port;
private Socket SocketServer;
public ArrayList Clients;
public delegate void ServiceWork(Socket forClient, String strMessage);
public event ServiceWork DoServiceWork;
#region 该定义用于处理接收数据分包
/// <summary>
/// 当前客户端状态
/// </summary>
class Cls_ClientStata
{
/// <summary>
/// 当前连接客户端
/// </summary>
public Socket client;
/// <summary>
/// 当前接收到的数据
/// </summary>
public string data;
/// <summary>
/// 用于存储接收的数据,最后转换为 string 赋值 data
/// </summary>
public List<byte> byteSource = new List<byte>();
/// <summary>
/// 每次接收的数据长度,实际可能没有这么长,需要根据实际情况处理
/// </summary>
public byte[] buffer=new byte[1024];
/// <summary>
/// 需要接收的数据长度
/// </summary>
public int ReceiveDataLength;
/// <summary>
///
/// </summary>
/// <param name="s"></param>
/// <param name="d"></param>
public Cls_ClientStata(Socket s)
{
client = s;
}
}
#endregion
/// <summary>
/// 实例服务器端Socket
/// </summary>
///<param name="P">端口号</param>
///<param name="ip">这里请使用Any,否则可能服务无法从外网访问</param>
public Cls_SocketServer(IPAddress ip, int P)
{
ServerIP = ip;
Port = P;
Clients = new ArrayList();
}
/// <summary>
/// 开始服务,可以创建客户连接
/// </summary>
/// <returns></returns>
public bool StartServer()
{
try
{
//获取IP地址
IPEndPoint ipep = new IPEndPoint(ServerIP, Port);
//实例化Socket
SocketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//将Socket与指定IP绑定
SocketServer.Bind(ipep);
//Socket 开始监听,设置监听队列的长度
SocketServer.Listen(10000);
SocketServer.BeginAccept(new AsyncCallback(ClientAccepted), SocketServer);
return true;
}
catch(Exception ex)
{
return false;
}
}
/// <summary>
/// 接受客户连接
/// </summary>
/// <param name="ar"></param>
private void ClientAccepted(IAsyncResult ar)
{
try
{
var socket = ar.AsyncState as Socket;//这里应该是SocketServer
//这就是客户端的Socket实例,我们后续可以将其保存起来
var client = socket.EndAccept(ar);//连接到的客户端
Clients.Add(client);//加入当前连接客户端列表
Cls_ClientStata ccs = new Cls_ClientStata(client);
//接收客户端的消息(这个和在客户端实现的方式是一样的)
client.BeginReceive(ccs.buffer, 0, ccs.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), ccs);
//准备接受下一个客户端请求
socket.BeginAccept(new AsyncCallback(ClientAccepted), socket);
}
catch
{
}
}
/// <summary>
/// 接收收到的信息
/// </summary>
/// <param name="ar"></param>
private void ReceiveMessage(IAsyncResult ar)
{
try
{
//使用自定义类来存储数据,以便于区分是哪个客户端发来的信息
Cls_ClientStata ccs = (Cls_ClientStata)ar.AsyncState;
Socket client = ccs.client;
int length = client.EndReceive(ar);
if (length == 0)
{//如果接收不到数据
client.Close();
return;
}
/// 虽然设置了 css.buffer 的长度为1024,但实际接收数据时,不一定能
/// 接收到1024的数据,如果此时直接认为是接收了1024,那么收到的数据
/// 就会多出空数据来,这样最终的收到的数据就会与发送的不一致,由其
/// 是在发送文件时,收到的文件将是不可用,不可以打开的。
byte[] tmpbyte = new byte[length];
Array.Copy(ccs.buffer, 0, tmpbyte, 0, length);
ccs.byteSource.AddRange(tmpbyte);//接收数据
#region 使用长度来标记是否已接收结束
if (ccs.ReceiveDataLength <= 0
&& ccs.byteSource.Count>=4)
{//还未计算接收长度,同时,接收到的长度已经大于或等于长度位长度
byte[] byteLengthg = new byte[4];
Array.Copy(ccs.byteSource.ToArray(), 0, byteLengthg, 0, 4);
ccs.ReceiveDataLength = Cls_WaterSocketMessage.byteArrayToInt(byteLengthg);//使转换方式与JAVA一致
//ccs.ReceiveDataLength = BitConverter.ToInt32(ccs.byteSource.ToArray(),0);
}
if (ccs.byteSource.Count >= ccs.ReceiveDataLength + 4)
{//数据已全部接收到
if (DoServiceWork != null)
{//返回方法不为空
ccs.data = Encoding.UTF8.GetString(ccs.byteSource.ToArray(), 4, ccs.ReceiveDataLength);
//实际使用中发现会出现数据传输错误,故加入哈希验证,减少错误数据读取率
int indexf = ccs.data.LastIndexOf('\f');
string resultData = ccs.data.Substring(0, indexf);
string hashData = ccs.data.Substring(indexf + 1, ccs.data.Length - indexf - 1);
if (Cls_WaterSocketMessage.GetHashValue(resultData) == hashData)
{//哈希值字符串比较
DoServiceWork(ccs.client, resultData);
}
else
{
DoServiceWork(ccs.client, "FALSE");
}
}
ccs.client.Close();//结束连接
return;
}
//接收下一个消息(因为这是一个递归的调用,所以这样就可以一直接收消息了)
client.BeginReceive(ccs.buffer, 0, ccs.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), ccs);
#endregion
}
catch(Exception ex)
{
}
}
/// <summary>
/// 结束服务
/// </summary>
public void Stop()
{
try
{
SocketServer.Shutdown(SocketShutdown.Both);
SocketServer.Close();
foreach (Socket s in Clients)
{
s.Shutdown(SocketShutdown.Both);
s.Close();
}
}
catch (Exception ex)
{
//throw new Exception(ex.Message);
}
}
/// <summary>
/// 发送网络信息
/// </summary>
/// <param name="s">要发送的客户端</param>
/// <param name="ms">要发送的信息</param>
public void SendMessage(Socket s, string ms)
{
if (!s.Poll(500, SelectMode.SelectRead))
{
byte[] sendData = Encoding.UTF8.GetBytes(ms); //报文内容转 byte
byte[] hashcode = Encoding.UTF8.GetBytes("\f" + Cls_WaterSocketMessage.GetHashValue(ms));//报文内容的哈希值
byte[] sendHead = Cls_WaterSocketMessage.intToByteArray(sendData.Length + hashcode.Length);//报文头,使转换方式与JAVA一致
//byte[] sendHead = BitConverter.GetBytes(sendData.Length + hashcode.Length);//报文头
//发送报文长度,int 占4个byte
s.Send(sendHead); //发送报文头
s.Send(sendData); //发送报文信息
s.Send(hashcode); //发送信息哈希验证码
}
}
}
}
if (client.Connected)
{
byteSource.AddRange(receiveBuffer);//接收数据
//检查数据中是否有结尾标记
int REnd = client.EndReceive(ar);
string strReceiveData = Encoding.UTF8.GetString(receiveBuffer, 0, REnd);
if (!string.IsNullOrEmpty(strReceiveData))
............
int REnd = client.EndReceive(ar);
byte[] tmpbyte = new byte[REnd];
Array.Copy(receiveBuffer, 0, tmpbyte, 0, REnd);
byteSource.AddRange(tmpbyte);//接收数据
//检查数据中是否有结尾标记
string strReceiveData = Encoding.UTF8.GetString(receiveBuffer, 0, REnd);
if (!string.IsNullOrEmpty(strReceiveData))
private onReceive(_msg:any = null):void{
// console.log("接收数据");
// _msg为ArrayBuffer
// 强制转换类型
let data:ArrayBuffer = _msg;
// Log.debug("recev data bytes length:" + data.byteLength);
// 实现Marshal
let unmarshalResult:GUnmarshalResult= this.protocol.unmarshal(data);
if(unmarshalResult.status != GUnmarshalResult.UNMARSHAL_STATUS_OK){
g.common.Log.error("unmarshal failed.");
return;
}
let pack:any = unmarshalResult.pack;
// Log.debug("get pack:" + pack);
// 通知消息接收
GNet.onRecv(this, pack);
}
// 将字节流转换为包对象
// 由于TS无法返回多个返回值,所以返回对象
public unmarshal(_data:ArrayBuffer):GUnmarshalResult{
// TODO:这里做了一个假设:websocket已经处理好了粘包和分包问题
// 准备参数
let pack:Pack = null;
let status:number = GUnmarshalResult.UNMARSHAL_STATUS_OK;
do{
// 判定数据长度必须大于HEADER_SIZE
let dataSize:number = _data.byteLength;
if(dataSize < Pack.HEADER_SIZE){
status = GUnmarshalResult.UNMARSHAL_STATUS_ERROR;
break;
}
// 获取bodySize,cmd和seqNum
let byte:Byte = new Byte(_data);
byte.endian = Protocol.ENDIAN;
let bodySize:number = byte.getUint32();
let cmd:number = byte.getUint32();
let seqNum:number = byte.getUint32();
// 获取body
let body:ArrayBuffer = _data.slice(Pack.HEADER_SIZE, dataSize);
// 生成pack
pack = new Pack(cmd, body, seqNum);
}while(false);
// 生成result,并返回
let result:GUnmarshalResult = new GUnmarshalResult();
result.pack = pack;
result.status = status;
return result;
}
func Unmarshal(_data []byte) (interface{}, int32) {
// 校验_data的长度必须大于HEADER_SIZE
dataSize := uint32(len(_data))
if dataSize < HEADER_SIZE {
return nil, e2.ERR_GATE_PROTOCOL_ERROR
}
// 获取BodySize
endian := binary.LittleEndian
bodySize := endian.Uint32(_data)
// 再次检查长度
fullSize := bodySize + HEADER_SIZE
if dataSize < fullSize {
return nil, e2.ERR_GATE_PROTOCOL_ERROR
}
// 获取cmd
cmd := endian.Uint32(_data[4:])
// 获取seqNum
seqNum := endian.Uint32(_data[8:])
// 生成package
// TODO:这里有一个拷贝!
pack := &Pack{}
pack.BodySize = bodySize
pack.CMD = cmd
pack.SeqNum = seqNum
pack.Body = make([]byte, bodySize)
copy(pack.Body, _data[HEADER_SIZE:fullSize])
return pack, e.OK
}
ReciveData = Encoding.UTF8.GetString(byteSource.ToArray());
int start = ReciveData.IndexOf("DATESTART") + "DATESTART".Length;
int end = ReciveData.IndexOf("DATEEND");
ReciveData = ReciveData.Substring(start, end - start);
/// <summary>
/// 发送网络信息
/// </summary>
/// <param name="s">要发送的客户端</param>
/// <param name="ms">要发送的信息</param>
public void SendMessage(Socket s, string ms)
{
if (!s.Poll(500, SelectMode.SelectRead))
{
s.Send(Encoding.UTF8.GetBytes(
"DATESTART" //报文开头
+ ms //报文内容
+ "\f" //报文与其哈希值的分隔符
+ Cls_WaterSocketMessage.GetHashValue(ms) //报文内容的哈希值
+ "DATEENDDATEEND")); //这里连续发送两个结束符,确保总有一个会被收到。
}
}