最近在用Socket 做局域网内客户端和服务器端通讯的程序(也可以用做客户端和客户端间的通讯)。先贴出收发的方法,其他的方法我会不断的更新。欢迎大家留言,互相交流。
发送的报文头信息为Struct类型,发送数据类型可以是String 也可以是一个类。在发送Struct类型或发送类时,必须先将这个类序列化为流,接收时再将流反序列化为对象。接收的缓冲区大小设为1024,先接收报文头,再根据报文头中发送数据的长度来接收数据(当然,也可以开一个很大的缓冲区来接数据,但可能会比较浪费资源)。
1、发送的方法。
在调用这个方法时,需要在实例化类时传入两个参数:目标IP和目标计算机的监听端口号。
public int CMSend(Object tcpHeader, Object objData, int outTime)
{
int flag = 0;
try
{
StartClient();
TcpHead structHead = (TcpHead)tcpHeader;
byte[] btyData = null;
byte[] btySendHead = new byte[32];
string strData = string.Empty;
switch (structHead.MessageType)
{
case "String":
strData = objData.ToString();
btyData = Encoding.ASCII.GetBytes(strData);
structHead.MessageLength = strData.Length;
break;
case "BaseDataContainer":
btyData = TransDataToByteArray(objData, BasePage.enumParamType.BaseDataContainer.ToString());
structHead.MessageLength = btyData.Length;
break;
default:
break;
}
btySendHead = TransDataToByteArray(structHead, BasePage.enumParamType.Struct.ToString());
byte[] bytSendData = new byte[btySendHead.Length + btyData.Length];
btySendHead.CopyTo(bytSendData, 0);
btyData.CopyTo(bytSendData, btySendHead.Length);
if (m_clientSocket == null || m_clientSocket.Connected == false)
{
throw new ArgumentException("參數socket 為null,或者未連接到遠程計算機");
}
if (bytSendData == null || bytSendData.Length == 0)
{
throw new ArgumentException("參數buffer 為null ,或者長度為 0");
}
int left = bytSendData.Length;
int sndLen = 0;
while (true)
{
if ((m_clientSocket.Poll(outTime * 1000000, SelectMode.SelectWrite) == true))// 收集了足够多的傳出數據后開始發送
{
sndLen = this.m_clientSocket.Send(bytSendData, sndLen, left, SocketFlags.None);
left -= sndLen;
if (left == 0)
{ // 數據已經全部發送
flag = 0;
break;
}
else
{
if (sndLen > 0)
{ // 數據已經部分被發送
continue;
}
else
{ // 發送數據發生錯誤
flag = -2;
break;
}
}
}
else
{ // 超時退出
flag = -1;
break;
}
}
}
catch (System.NullReferenceException e)
{
MessageBox.Show("連接失敗", "INF:001", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception e)
{
MessageBox.Show("發送失敗", "INF:001", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
finally
{
this.close();
}
return flag;
}
2、接收方法
在调用这个方法时,需要在实例化类时传入一个参数:本地的监听端口号。
public Hashtable CMReceive()
{
if (firstFlag == true)
{
tcpListener = new TcpListener(receivePort);
tcpListener.Start();
firstFlag = false;
}
while (true)
{
listenSocket = tcpListener.AcceptSocket();
string strTcpHead = string.Empty;
byte[] bytTcpHead = new byte[1024];
byte[] receiveByte = new byte[1024];
byte[] bytReceiveData = null;
TcpHead structReceiveHead;
object objStructReceiveHead;
int bytes = 0;
int count = 0;
int messageLength;
int buffLength;
bool isHead = true;
while (true)
{
bytes = listenSocket.Receive(receiveByte, receiveByte.Length, SocketFlags.None);
bytTcpHead = receiveByte;
isHead = false;
break;
}
objStructReceiveHead = TransByteArrayToObject(bytTcpHead, BasePage.enumParamType.Struct.ToString());
structReceiveHead = (TcpHead)objStructReceiveHead;
messageLength = structReceiveHead.MessageLength;
if (messageLength % 1024 == 0)
{
buffLength = messageLength / 1024;
}
else
{
buffLength = messageLength / 1024 + 1;
}
if (count == 0)
{
bytReceiveData = new byte[buffLength * 1024];
}
while (true)
{
bytes = listenSocket.Receive(receiveByte, receiveByte.Length, SocketFlags.None);
if (bytes <= 0)
break;
receiveByte.CopyTo(bytReceiveData, count * 1024);
count++;
}
object objReceiveData = TransByteArrayToObject(bytReceiveData, structReceiveHead.MessageType);
Hashtable htTcpHead = new Hashtable();
htTcpHead.Add("objStructReceiveHead", structReceiveHead);
htTcpHead.Add("objReceiveData", objReceiveData);
return htTcpHead;
}
}
3、把对象转化为字节流的方法
public byte[] TransDataToByteArray(Object objectParam, string sendDataType)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream();
byte[] buff = null;
switch (sendDataType)
{
case "String":
string tempStr = objectParam.ToString();
Char[] tempChar = tempStr.ToCharArray();
buff = System.Text.Encoding.UTF8.GetBytes(tempChar);
break;
case "BaseDataContainer":
bf.Serialize(memoryStream, objectParam);
buff = memoryStream.ToArray();
break;
case "Struct":
bf.Serialize(memoryStream, objectParam);
byte[] tempByte = memoryStream.ToArray();
buff = new Byte[1024];
tempByte.CopyTo(buff, 0);
for (int k = tempByte.Length; k < 1024; k++)
{
buff.SetValue(Byte.Parse("1"), k);
}
break;
default:
break;
}
return buff;
}
4、把字节流反转为对象的方法
public object TransByteArrayToObject(byte[] byteTemp, string paramType)
{
if (paramType.Equals("String"))
{
string object_temp = System.Text.Encoding.UTF8.GetString(byteTemp);
return object_temp;
}
else if (paramType.Equals("BaseDataContainer"))
{
MemoryStream memoryStream = new MemoryStream(byteTemp);
BinaryFormatter bf = new BinaryFormatter();
BaseDataContainer object_temp = (BaseDataContainer)bf.Deserialize(memoryStream);
return object_temp;
}
else if (paramType.Equals("Struct"))
{
MemoryStream memoryStream = new MemoryStream(byteTemp);
BinaryFormatter bf = new BinaryFormatter();
TcpHead object_temp = (TcpHead)bf.Deserialize(memoryStream);
return object_temp;
}
else
{
return "Exception";
}
}
5、获取本地IP
#region 取得本地IP
public string GetHostIP()
{
string strHostname = Dns.GetHostName();
IPHostEntry strIP = Dns.GetHostEntry(strHostname);
string localIPStr = strIP.AddressList[0].ToString();
IPAddress localIP = IPAddress.Parse(localIPStr);
return localIPStr;
}
#endregion
6、连接目标计算机
public void StartClient()
{
//Connect to a remote device.
try
{
IPHostEntry ipHostInfo = Dns.Resolve(this.m_strServerIP);
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, this.m_nServerPort);
//Create a TCP/IP socket.
this.m_clientSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
//Connect to the remote endpoint.
if (m_clientSocket.Connected)
{
close();
}
this.m_clientSocket.Connect(remoteEP);
}
catch (Exception e)
{
this.ReportError("StartClient found a error:/r/n" + e.ToString());