1.保存消息数据的类:
/// <summary>
/// 消息命令类型
/// </summary>
public enum msgCommand
{
/// <summary>
/// 空
/// </summary>
None,
/// <summary>
/// 登录
/// </summary>
Login,
/// <summary>
/// 退出
/// </summary>
Exit,
/// <summary>
/// 更改密码
/// </summary>
ChangePwd,
/// <summary>
/// 注册
/// </summary>
Register,
/// <summary>
/// 获取在线用户列表
/// </summary>
GetUserList,
/// <summary>
/// 获取通知
/// </summary>
GetNotice
}
/// <summary>
/// 消息类型
/// </summary>
public enum msgType
{
/// <summary>
///空消息
/// </summary>
None,
/// <summary>
///文本消息
/// </summary>
SendText,
/// <summary>
///发送文件
/// </summary>
SendFile
}
/// <summary>
/// 消息发送状态(用于消息循环接收的开始和技术标识)
/// </summary>
public enum msgSendState
{
None, //空
single, //单条消息,一次性接收
start, //消息开始
sending,//消息发送中
end //消息结束
}
/// <summary>
/// 消息类,标记为可序列化
/// </summary>
[Serializable]
public class ClassMsg
{
public string sendIP = string.Empty; //发送方IP
public string sendProt = string.Empty; //发送方监听端口
public msgCommand command = msgCommand.None; //命令枚举
public msgType type = msgType.None; //消息类型枚举
public msgSendState msgState = msgSendState.None; //消息状态枚举
public byte[] Data; //消息内容
}
2.客户端:(只写了发送的方法)
class tcpSocketClient
{
public void sendMsg()
{
IPAddress IP = Dns.GetHostAddresses(Dns.GetHostName())[3];
while (true)
{
Console.WriteLine("enter the msg:");
Socket socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
IPEndPoint Ip = new IPEndPoint(IP, 3000);
socketSend.Connect(Ip);
ClassMsg msg = new ClassMsg();
string strMsg = Console.ReadLine();
msg.type=msgType.SendText;
msg.sendIP=Dns.GetHostAddresses(Dns.GetHostName())[3].ToString();
msg.Data = Encoding.Default.GetBytes(strMsg);
MemoryStream mStream = new MemoryStream();
BinaryFormatter bformatter = new BinaryFormatter(); //二进制序列化类
bformatter.Serialize(mStream, msg); //将消息类转换为内存流
mStream.Flush();
byte[] buffer = new byte[1024];
mStream.Position = 0; //将流的当前位置重新归0,否则Read方法将读取不到任何数据
while (mStream.Read(buffer, 0, buffer.Length) > 0)
{
socketSend.Send(buffer); //从内存中读取二进制流,并发送
}
socketSend.Close();
Console.WriteLine("消息发送完毕!输入Y退出,其他继续:");
string strEnter = Console.ReadLine();
if (strEnter == "Y" || strEnter == "y")
{
break;
}
}
}
}
3.服务器端:(只写了循环接收)
监听方法:
public void Listen()
{
Socket tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
IPEndPoint IP = new IPEndPoint(Dns.GetHostAddresses(Dns.GetHostName())[3], 3000);
Console.WriteLine("监听已启动" + Dns.GetHostAddresses(Dns.GetHostName())[3]);
tcpSocket.Bind(IP);
tcpSocket.Listen(10);
while (true)
{
Socket socketAccpet = tcpSocket.Accept();
TcpSocketReceive re = new TcpSocketReceive(socketAccpet);
Thread thread = new Thread(new ThreadStart(re.ReceiveMsg));
thread.Start();//可能有并发请求,所以消息的接收也需要在子线程中处理
}
}
说明:因为Socket的Listen方法会一直处于阻塞状态,所以不能够在主线程直接使用,否则应用程序将不能再做其他事情。所以有了下面的另外一个Listen方法。
public void Listen()
{
TcpSocket Tsocket = new TcpSocket();
Thread TcpThread = new Thread(new ThreadStart(Tsocket.Listen));
TcpThread.Start();//启动一个子线程来调用socket的监听方法
}
接收消息的方法:
/// <summary>
/// 接收消息
/// </summary>
/// <param name="socketAccept"></param>
public void ReceiveMsg()
{
byte[] buffer = new byte[1024];
MemoryStream mStream = new MemoryStream();
mStream.Position = 0;
while (true)
{
int ReceiveCount = socketAccept.Receive(buffer,1024,0);
if (ReceiveCount ==0)
{
break;//接收到的字节数为0时break
}
else
{
Console.WriteLine("成功获取到数据");
mStream.Write(buffer,0,ReceiveCount); //将接收到的数据写入内存流
}
}
mStream.Flush();
mStream.Position = 0;
BinaryFormatter bFormatter = new BinaryFormatter();
if (mStream.Capacity > 0)
{
ClassMsg msg = (ClassMsg)bFormatter.Deserialize(mStream);//将接收到的内存流反序列化为对象
Console.WriteLine("接收到来自"+msg.sendIP+"的信息内容:"+Encoding.Default.GetString(msg.Data));
}
else
{
Console.WriteLine("接收到的数据为空。");
}
socketAccept.Close();
Console.WriteLine("线程执行完毕。");
}