using System;
using System.Net.Sockets;
namespace Server
{
public class Conn
{
public const int BUFFER_SIZE = 1024;
public Socket socket;
public bool isUse = false;
public byte[] readBuff = new byte[BUFFER_SIZE];
public int buffCount = 0;
public byte[] lenBytes = new byte[sizeof(UInt32)];
public Int32 msgLength = 0;
public Conn()
{
readBuff = new byte[BUFFER_SIZE];
}
// 初始化
public void Init(Socket socket)
{
this.socket = socket;
isUse = true;
buffCount = 0;
}
public int BuffRemain()
{
return BUFFER_SIZE - buffCount;
}
public string GetAdress()
{
if (!isUse) return " 无法获取地址 ";
return socket.RemoteEndPoint.ToString();
}
public void Close()
{
if (!isUse) return;
socket.Close();
isUse = false;
Console.WriteLine(" [ 关闭连接 ] " + GetAdress());
}
/* //发送协议
public void Send(ProtocolBase protocol)
{
}*/
}
}
服务器
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Server
{
public class ServNet
{
public Socket listenfd;
public Conn[] conns;
public int maxConn = 50;
//获取连接池索引,返回负数表示获取失败
public int NewIndex()
{
if (conns == null) return -1;
for(int i = 0; i < conns.Length; i++)
{
if (conns[i] == null)
{
conns[i] = new Conn();
return i;
}else if (!conns[i].isUse)
{
return i;
}
}
return -1;
}
public void Start(string host,int port)
{
conns = new Conn[maxConn];//连接池
for(int i = 0; i < maxConn; i++)
{
conns[i] = new Conn();
}
//socket
listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAdr = IPAddress.Parse(host);
IPEndPoint ipEp = new IPEndPoint(ipAdr, port);
listenfd.Bind(ipEp);
listenfd.Listen(maxConn);
listenfd.BeginAccept(AcceptCb, null);
Console.WriteLine("[服务器] 启动成功 ");
}
private void AcceptCb(IAsyncResult ar)
{
try
{
Socket socket = listenfd.EndAccept(ar);
int index = NewIndex();
if (index < 0)
{
socket.Close();
Console.WriteLine("[ 警告 ] 连接已满 ");
}
else
{
Conn conn = conns[index];
conn.Init(socket);
string adr = conn.GetAdress();
Console.WriteLine("客户端 [ " + adr + " ] conn 池 ID:" + index);
conn.socket.BeginReceive(conn.readBuff, conn.buffCount, conn.BuffRemain(), SocketFlags.None, ReceiveCb, conn);
}
}catch(Exception e)
{
Console.WriteLine("AcceptCb 失败:" + e.Message);
}
listenfd.BeginAccept(AcceptCb, null);
}
private void ReceiveCb(IAsyncResult ar)
{
Conn conn = (Conn)ar.AsyncState;
try
{
int count = conn.socket.EndReceive(ar);
//关闭信号
if (count <= 0)
{
Console.WriteLine("收到 [ " + conn.GetAdress() + " 客户端断开连接 ");
conn.Close();
return;
}
conn.buffCount += count;
ProcessData(conn);
conn.socket.BeginReceive(conn.readBuff, conn.buffCount, conn.BuffRemain(), SocketFlags.None, ReceiveCb, conn);
}
catch(Exception e)
{
Console.WriteLine("收到 [ " + conn.GetAdress() + " ] 断开连接 {原因: "+e.Message+"}");
conn.Close();
}
}
private void ProcessData(Conn conn)
{
if (conn.buffCount < sizeof(Int32)) { return; }
Array.Copy(conn.readBuff, conn.lenBytes, sizeof(Int32));
conn.msgLength = BitConverter.ToInt32(conn.lenBytes, 0);
if (conn.buffCount < conn.msgLength + sizeof(Int32)) { return; }
/**************************/
string str = Encoding.UTF8.GetString(conn.readBuff, sizeof(Int32), conn.msgLength);
Console.WriteLine(" 收到 [ " + conn.GetAdress() + " ] " + str);
/**************************/
int count = conn.buffCount - conn.msgLength - sizeof(Int32);
Array.Copy(conn.readBuff, sizeof(Int32) + conn.msgLength,conn.readBuff,0,count);
conn.buffCount = count;
if (conn.buffCount > 0) ProcessData(conn);
}
public void Send(Conn conn, string str)
{
byte[] bytes = Encoding.UTF8.GetBytes(str);
byte[] length = BitConverter.GetBytes(bytes.Length);
byte[] sendbuff = length.Concat(bytes).ToArray();
try
{
conn.socket.BeginSend(sendbuff, 0, sendbuff.Length, SocketFlags.None, null, null);
}catch(Exception e)
{
Console.WriteLine("[ 发送消息失败 ]" + conn.GetAdress() + " : {" + e.Message+"}");
}
}
public void Close()
{
for(int i = 0; i < conns.Length; i++)
{
Conn conn = conns[i];
if (conn == null) continue;
if (!conn.isUse) continue;
lock (conn) { conn.Close(); }
}
}
}
}
客户端
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
namespace Server
{
public class ClinNet
{
public Conn listenfd;
public void Start(string host, int port)
{
listenfd = new Conn();
//socket
listenfd.Init(new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp));
IPAddress ipAdr = IPAddress.Parse(host);
IPEndPoint ipEp = new IPEndPoint(ipAdr, port);
listenfd.socket.Connect(ipEp);
listenfd.socket.BeginReceive(listenfd.readBuff, listenfd.buffCount, listenfd.BuffRemain(), SocketFlags.None, ReceiveCb, listenfd);
Console.WriteLine("[客户端] 启动成功 ");
}
private void ReceiveCb(IAsyncResult ar)
{
Conn conn = (Conn)ar.AsyncState;
try
{
int count = conn.socket.EndReceive(ar);
//关闭信号
if (count <= 0)
{
Console.WriteLine("收到 [ " + conn.GetAdress() + " 服务器已断开连接 ");
conn.Close();
return;
}
conn.buffCount += count;
ProcessData(conn);
conn.socket.BeginReceive(conn.readBuff, conn.buffCount, conn.BuffRemain(), SocketFlags.None, ReceiveCb, conn);
}
catch (Exception e)
{
Console.WriteLine("收到 [ " + conn.GetAdress() + " ] 断开连接 { 错误: " + e.Message + "}");
conn.Close();
}
}
private void ProcessData(Conn conn)
{
if (conn.buffCount < sizeof(Int32)) { return; }
Array.Copy(conn.readBuff, conn.lenBytes, sizeof(Int32));
conn.msgLength = BitConverter.ToInt32(conn.lenBytes, 0);
if (conn.buffCount < conn.msgLength + sizeof(Int32)) { return; }
/**************************/
string str = System.Text.Encoding.UTF8.GetString(conn.readBuff, sizeof(Int32), conn.msgLength);
Console.WriteLine(" 收到 [ " + conn.GetAdress() + " ] " + str);
/**************************/
int count = conn.buffCount - conn.msgLength - sizeof(Int32);
Array.Copy(conn.readBuff, sizeof(Int32) + conn.msgLength, conn.readBuff, 0, count);
conn.buffCount = count;
if (conn.buffCount > 0) ProcessData(conn);
}
public void Send(string str)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(str);
byte[] length = BitConverter.GetBytes(bytes.Length);
byte[] sendbuff = length.Concat(bytes).ToArray();
try
{
listenfd.socket.Send(sendbuff);
}
catch (Exception e)
{
Console.WriteLine("发送消息失败: "+e.Message);
}
}
}
}

这是一个使用C#编写的简单TCP服务器和客户端应用程序。服务器端创建了一个连接池来管理客户端连接,当有新的客户端连接时,会将其加入到连接池中,并开始接收数据。接收到数据后,通过`ProcessData`方法解析并打印。客户端则负责连接到服务器并接收服务器发送的数据。整个程序展示了如何使用Socket进行基本的网络通信。
502

被折叠的 条评论
为什么被折叠?



