客户端与服务端通讯socket
封装此类,是为了方便维护客户端和服务端建立连接后返回的socket
包含了所需要的基础的socket 以及 该socket所对应的id号,方便进行管理
cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace TechTcpServerTest2
{
internal class ClientTcpSockt
{
private static int CLIENT_NUMBER = 0;
public int clientID = 0;
private Socket? socket;
public ClientTcpSockt(Socket _socket)
{
socket = _socket;
clientID = CLIENT_NUMBER;
++CLIENT_NUMBER;
}
public void Send(string info)
{
if (socket != null)
{
try
{
socket.Send(Encoding.UTF8.GetBytes(info));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
public void Receive()
{
if (socket != null)
{
try
{
if (socket.Available > 0)
{
byte[] buffer = new byte[1024 * 5];
int num = socket.Receive(buffer);
ThreadPool.QueueUserWorkItem(HandleMsg, Encoding.UTF8.GetString(buffer, 0, num));
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
private void HandleMsg(object obj)
{
string info = (string)obj;
if (socket != null)
{
Console.WriteLine("{0}客户端,信息:{1}", socket.RemoteEndPoint, info);
}
}
public void Close()
{
if (socket != null)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
socket = null;
}
}
}
}
服务端socket
此类具有基础的socket 以及 一个客户端类的字典,按照 特定的id与socket进行对应
对于客户端的连接请求以及消息的接收处理依旧采用多线程去处理
对于accept一直循环去监听,如果有新连接就加入到字典当中
对于receive,就一直循环的调用字典中存储对象的receive方法
关闭对客户端的连接,只需要循环调用字典内 刚刚封装的客户端-服务端socket对象中的关闭方法就行
cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace TechTcpServerTest2
{
internal class ServerTcpSocket
{
private Socket socket;
private Dictionary<int, ClientTcpSockt> clientDic = new Dictionary<int, ClientTcpSockt>();
private bool isConnected;
public bool IsConnected => isConnected;
public void Start(string ip, int port, int num)
{
isConnected = false;
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(ip), port);
socket.Bind(ipPoint);
socket.Listen(num);
ThreadPool.QueueUserWorkItem(Accept);
ThreadPool.QueueUserWorkItem(Receive);
}
public void Accept(object obj)
{
while (!isConnected)
{
try
{
Socket client = socket.Accept();
ClientTcpSockt clientTcpSockt = new ClientTcpSockt(client);
clientDic.Add(clientTcpSockt.clientID, clientTcpSockt);
clientTcpSockt.Send("服务器连接成功");
}
catch (Exception e)
{
Console.WriteLine("客户端连接出错 " + e.Message);
}
}
}
public void Receive(object obj)
{
while (!isConnected)
{
try
{
if (clientDic.Count > 0)
{
foreach (var item in clientDic.Values)
{
item.Receive();
}
}
}
catch (Exception e)
{
Console.WriteLine("客户端接收出错 " + e.Message);
}
}
}
public void Close()
{
foreach(var item in clientDic.Values)
{
item.Close();
}
clientDic.Clear();
isConnected = true;
socket.Shutdown(SocketShutdown.Both);
socket.Close();
socket = null;
}
public void Broadcast(string info)
{
if (socket != null)
{
foreach (var item in clientDic.Values)
{
item.Send(info);
}
}
}
}
}
启动
开始先初始化一个与服务相关的socket类对象,调用前面所写的start方法初始化绑定ip地址、端口号、监听大小
然后该类对象会自动进行处理相应的客户端连接,以及相关的通讯工作。对于客户端,最基本的代码connect就可以连接该服务器并进行通讯
cs
namespace TechTcpServerTest2
{
internal class Program
{
static void Main(string[] args)
{
ServerTcpSocket socket = new ServerTcpSocket();
socket.Start("127.0.0.1", 8080, 1024);
Console.WriteLine("服务器开启");
while(true)
{
string input = Console.ReadLine();
if (input == "Quit")
{
socket.Close();
}
else if (input.Substring(0, 2) == "B:")
{
socket.Broadcast(input.Substring(2));
}
}
}
}
}
启动客户端和该新的服务端后,可以发现依然能够正常连接