作为服务器端,只需要知道自己需要监听的IP和端口号,就可以监听到前来通讯的服务器端。
可以使用一个结构体来封装TCP通讯所需要的参数。
static public Socket NewServer = null;
static public Socket NewClient = null;
public struct TcpSetPara
{
public IPAddress m_IP; //监听的IP
public int m_Port; //监听的Port
public UInt16 CommTCPTimeSet; //发送完报文后等待一段时间接收
}
接着初始化参数
public static void InitTcpPara()
{
m_TcpSetPara.CommTCPTimeSet = 200;
m_TcpSetPara.m_IP = GetIpAddress(); //获取当前主机的IP
m_TcpSetPara.m_Port = 502;
}
//获取当前主机的IP
public static IPAddress GetIpAddress()
{
string name = Dns.GetHostName();
string IpStr = "";
IPAddress[] ipadrlist = Dns.GetHostAddresses(name);
foreach (IPAddress ipa in ipadrlist)
{
if (ipa.AddressFamily == AddressFamily.InterNetwork)
{
IpStr = ipa.ToString();
}
}
IPAddress ip = IPAddress.Parse(IpStr);
return ip;
}
启动连接,这里采用的是异步监听
static public void Connect()
{
//初始化TCP参数
InitTcpPara();
IPEndPoint point = new IPEndPoint(m_TcpSetPara.m_IP, m_TcpSetPara.m_Port);
NewServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
NewServer.Bind(point);
NewServer.Listen(50);
NewServer.BeginAccept(new AsyncCallback(Accept), NewServer);
}
来看看Accept这个方法里都干了什么
private static void Accept(IAsyncResult socket)
{
Socket SockeServer = (Socket)socket.AsyncState;
// 在原始套接字上调用EndAccept方法,返回新的套接字
NewClient = SockeServer.EndAccept(socket);
bConnect = true;
//起两个线程,一个用来发送,一个用来接收
if (SendThread == null)
{
SendThread = new Thread(DataCommon.SendOperate);
SendThread.Start();
SendThread.IsBackground = true;
//SendThread.Priority = ThreadPriority.Normal;
}
if (ProcessRevThread == null)
{
ProcessRevThread = new Thread(DataCommon.ProcessRevMessage);
ProcessRevThread.Start();
ProcessRevThread.IsBackground = true;
//ProcessRevThread.Priority = ThreadPriority.Normal;
}
//为了确保当前的连接是有效的,需要不断检测,在这里用比较笨的办法
//由于在我的程序中,Connect这个方法本身是由线程启动的,所以在一个线程不断检测还是可以接收的
while (bConnect)
{
bool flagRead = false;
try
{
flagRead = NewClient.Poll(10, SelectMode.SelectRead);
}
catch(Exception ex)
{
//LogHelper.log(ex.ToString());
break;
}
if ((flagRead && (NewClient.Available == 0)) || !NewClient.Connected)
{
//这时可以确定网络连接出现问题,需要断开连接,重新连接
DisConnected();
bConnect = false;
ReConnect();
}
Thread.Sleep(1000);
}
这时候得到的NewClient是一个有效的Socket,可以用来接收客户端的消息和向客户端发送消息
接收和发送消息也分为同步和异步
先来看一下同步接收:
private static int recv_cmd(byte[] recvbuffer, int buffer_len)
{
int recvlen = 0;
try
{
Ethernet.Socket.ReceiveTimeout = 5000; //设置的接收消息超时
Ethernet.NewClient.Blocking = false;
recvlen = Ethernet.NewClient.Receive(recvbuffer, buffer_len, 0);
}
catch(Exception ex)
{
//Ethernet.bConnect = false;
//MessageBox.Show("通讯异常!", "提示");
//LogHelper.log(ex.Message.ToString());
return -1;
}
return recvlen;
}
再来看一下同步发送
public static bool send_cmd(byte[] send_buffer, int buffer_len)
{
bool bSend_succ = false;
try
{
Ethernet.Socket.Blocking = false;
Ethernet.Socket.SendTimeout = 500; //设置的发送超时
Ethernet.Socket.Send(send_buffer, buffer_len, 0);
bSend_succ = true;
}
catch(Exception ex)
{
//LogHelper.log(ex.Message.ToString());
bSend_succ = false;
}
return bSend_succ;
}
来看一下异步接收:
public static void ProcessMaintenenceMessage()
{
NewClient.BeginReceive(recvbuffer, 0, recvbuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), NewClient);
}
static void ReceiveCallback(IAsyncResult result)
{
Socket ts = (Socket)result.AsyncState;
try
{
ts.EndReceive(result);
result.AsyncWaitHandle.Close();
//接收到消息后开始处理消息的线程
//ProcessMessageThread = new Thread(ProcessOneKeyDataProcess);
//ProcessMessageThread.Start(recvbuffer);
//将数据存入到队列中
lock(m_OneKeyMaintence)
{
m_OneKeyMaintence.Enqueue(recvbuffer);
}
//等待100ms继续接收消息
Thread.Sleep(500);
recvbuffer = new byte[recvbuffer.Length];
ts.BeginReceive(recvbuffer, 0, recvbuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), ts);
}
catch(Exception ex) //Socket对象已关闭
{
//接收消息时出现异常,重新连接
DisConnect();
ReConnect();
//LogHelper.log(ex.Message.ToString());
return;
}
}
以上是做完项目后的一个大体梳理,如有问题,敬请指出