一、Socket和NetworkStream的区别:
在C#中,Socket和NetworkStream是用于进行网络通信的两种不同的API,Socket提供了更底层且灵活的网络通信功能,适用于对网络传输细节有较高要求的场景。而NetworkStream则是基于Socket的高级封装,提供了简化的读写接口,适用于大多数常见的网络通信任务。
二、使用步骤
1.Socket
tcp服务端
using System;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace ServerTcp
{
class Program
{
static void Main(string[] args)
{
//创建Socket
Socket ServerTcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定IP和端口
IPAddress iPAddress = new IPAddress(new byte[] { 127,0,0,1 });
EndPoint endPoint = new IPEndPoint(iPAddress, 7777);
ServerTcp.Bind(endPoint);
//监听,等待客户端进行链接
Console.WriteLine("开始监听");
ServerTcp.Listen(100);//开始监听,100为最大连接数
Console.WriteLine("等待客户端链接");
Socket client = ServerTcp.Accept();//接收客户端;实际上是暂停当前线程
//向客户端发送消息
string mess1 = "服务器正在运行";
byte[] buffer = Encoding.UTF8.GetBytes(mess1);//字符串转为字节
client.Send(buffer);
while(true)
{
//接收客户端的消息
byte[] data = new byte[1024];//定义缓存区
int length = client.Receive(data);//信息的有效长度
string mess2 = Encoding.UTF8.GetString(data, 0, length);
Console.WriteLine("向客户端发送的消息:" + mess2);
}
}
}
}
TCP客户端
using System;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace ClientTcp
{
class Program
{
static void Main(string[] args)
{
//创建Socket
Socket tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//请求与服务器连接
IPAddress ip = IPAddress.Parse("127.0.0.1");
EndPoint endPoint = new IPEndPoint(ip,7777);
tcpClient.Connect(endPoint);
//接收消息
byte[] buffer = new byte[1024];//定义缓存区
int length = tcpClient.Receive(buffer);//将接收的数组放入缓存区,并返回字节数
string message = Encoding.UTF8.GetString(buffer, 0, length);//对缓存区中的数据进行解码成字符串
Console.WriteLine("从服务端接收的信息:"+message);
while(true)
{
//发送消息
string str = Console.ReadLine();//输入发送的信息
tcpClient.Send(Encoding.UTF8.GetBytes(str));//将string转成字节流后,发送消息
}
}
}
}
UDP服务端
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace UdpServer
{
class Program
{
static void Main(string[] args)
{
//创建Socket
Socket udpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//绑定ip和端口
EndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7777);
udpServer.Bind(endPoint);
while (true)
{
//接收消息
EndPoint endPointSend = new IPEndPoint(IPAddress.Any, 0);//任意IP地址,任意端口
byte[] data = new byte[1024];
int length = udpServer.ReceiveFrom(data, ref endPointSend);
string message = Encoding.UTF8.GetString(data, 0, length);
Console.WriteLine("接收客户端发送的信息:" + message);
}
}
}
}
UDP客户端
using System;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace UdpClient
{
class Program
{
static void Main(string[] args)
{
//创建socket
Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
EndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7777);
while (true)
{
//发送消息
string message = Console.ReadLine();
udpClient.SendTo(Encoding.UTF8.GetBytes(message), endPoint);
}
}
}
}
2.NetworkStream
客户端
using System;
using System.Net.Sockets;
using System.Text;
namespace Client
{
class Program
{
static void Main(string[] args)
{
//服务器IP和端口
string serverIP = "127.0.0.1";
int serverPort = 7777;
//创建TCP客户端
TcpClient client = new TcpClient();
client.Connect(serverIP, serverPort);
//获取网络流
NetworkStream stream = client.GetStream();
//发送消息给服务器
string message = "这里是客户端!!";
byte[] data = Encoding.UTF8.GetBytes(message);
stream.Write(data, 0, data.Length);
Console.WriteLine("客户端发送消息:" + message);
// 读取服务器的响应
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine("客户端接收到信息:" + response);
// 关闭连接
stream.Close();
client.Close();
Console.WriteLine("客户端连接已关闭");
Console.ReadKey();
}
}
}
服务端
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace Server
{
class Program
{
static void Main(string[] args)
{
//定义ip和端口后开始监听
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
int port = 7777;
TcpListener listener = new TcpListener(ipAddress, port);
listener.Start();
Console.WriteLine("服务器正在运行,等待客户端连接");
//接收客户端
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("客户端已经连接");
//获取网络流
NetworkStream steam = client.GetStream();
//读取客户端发送的消息
byte[] buffer = new byte[1024];
int bytesRead = steam.Read(buffer, 0, buffer.Length);
string message = Encoding.UTF8.GetString(buffer,0,bytesRead);
Console.WriteLine("服务器接收到消息:" + message);
//发送响应给客户端
string response = "这里是服务器!!";
byte[] data = Encoding.UTF8.GetBytes(response);
steam.Write(data,0,data.Length);
Console.WriteLine("服务器发送信息:" + response);
//关闭连接
steam.Close();
client.Close();
listener.Stop();
Console.WriteLine("服务器连接关闭");
Console.ReadKey();
}
}
}
3.简单聊天室(Unity)
服务端
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace Learing
{
class Program
{
static List<Client> clientList = new List<Client>();
static Socket serverSocket;
static void Main(string[] args)
{
BindServerIPAndPort();
while(true)
{
Socket clientSocket = serverSocket.Accept();
Client client = new Client(clientSocket);
clientList.Add(client);
Console.WriteLine(((IPEndPoint)clientSocket.RemoteEndPoint).Address+"加入连接");
foreach(var item in clientList)
{
if(item.IsConnected)
{
item.SentInfoToServer(((IPEndPoint)item.clientSocket.RemoteEndPoint).Address+"加入房间");
}
}
}
}
//绑定服务端ip和端口
static void BindServerIPAndPort()
{
serverSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPAddress serverIP = IPAddress.Parse("127.0.0.1");
EndPoint serverPoint = new IPEndPoint(serverIP, 7777);
serverSocket.Bind(serverPoint);
serverSocket.Listen(100);
}
//广播数据
public static void BroadcastInfoToClient(string info)
{
List<Client> NotConnectedList = new List<Client>();
foreach (var item in clientList)
{
if(item.IsConnected)
{
item.SentInfoToServer(info);
}
else
{
NotConnectedList.Add(item);
}
}
foreach (var item in NotConnectedList)
{
clientList.Remove(item);
Console.WriteLine(((IPEndPoint)item.clientSocket.RemoteEndPoint).Address + "断开连接");
}
}
}
class Client
{
public Socket clientSocket;
Task client;
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
byte[] buffer = new byte[1024];
//初始化资源
public Client(Socket s)
{
clientSocket = s;
client= Task.Run(ReceiveServerBroadcastInfo);
}
//接收数据
void ReceiveServerBroadcastInfo()
{
if (cancellationTokenSource.IsCancellationRequested) return;
while(true)
{
if(clientSocket.Poll(10,SelectMode.SelectRead))
{
break;
}
buffer = new byte[1024];
try
{
int length = clientSocket.Receive(buffer);
string message = Encoding.UTF8.GetString(buffer, 0, length);
Program.BroadcastInfoToClient(message);//向其他客户端广播信息
Console.WriteLine("收到消息:" + message);
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
//发送数据
public void SentInfoToServer(string message)
{
byte[] data = Encoding.UTF8.GetBytes(message);
clientSocket.Send(data);
}
private bool isConnected;
public bool IsConnected
{
get
{
isConnected = clientSocket.Connected;
return isConnected;
}
}
~Client()
{
cancellationTokenSource.Cancel();
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
}
}
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
public class ClientManager : MonoBehaviour
{
[Header("服务器IP")]
public string ipAddress;
[Header("服务器Port")]
public int port;
[Header("信息输入框")]
public InputField inputText;
[Header("名称输入框")]
public InputField inputName;
[Header("连接服务器按钮")]
public Button connectedServerBtn;
[Header("发送信息按钮")]
public Button sendBtn;
[Header("聊天信息显示的Text")]
public Text ShowReceiveText;
Socket ClientServer=null;
Task client;
string tempInfo;
string message;
bool isConnected = false;
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
// Use this for initialization
void Start()
{
ConnectedToServer();
sendBtn.onClick.AddListener(SendMSG);
connectedServerBtn.onClick.AddListener(Test);
}
// Update is called once per frame
void Update()
{
if (!string.IsNullOrEmpty(message))
{
ShowReceiveText.text = ShowReceiveText.text + "\n" + message;
message = "";
}
}
//连接服务器
public void ConnectedToServer()
{
ClientServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ServerAddress = IPAddress.Parse(ipAddress);
EndPoint ServerPoint = new IPEndPoint(ServerAddress, port);
//开始连接
ClientServer.Connect(ServerPoint);
client = Task.Run(ReceiveMSG);
}
//接收消息
void ReceiveMSG()
{
if (cancellationTokenSource.IsCancellationRequested) return;
while (true)
{
if (ClientServer.Connected == false)
{
break;
}
byte[] data = new byte[1024];
int length = ClientServer.Receive(data);
message = Encoding.UTF8.GetString(data, 0, length);
}
}
//发送消息
void SendMSG()
{
if(isConnected)
{
tempInfo = inputText.text;
byte[] data = Encoding.UTF8.GetBytes(inputName.text + ":" + tempInfo);
ClientServer.Send(data);
}
}
void Test()
{
if(!isConnected)
{
isConnected = true;
connectedServerBtn.transform.GetChild(0).GetComponent<Text>().text = "断开";
}
else
{
isConnected = false;
connectedServerBtn.transform.GetChild(0).GetComponent<Text>().text = "连接";
}
}
//释放资源
private void OnApplicationQuit()
{
cancellationTokenSource.Cancel();
ClientServer.Shutdown(SocketShutdown.Both);
ClientServer.Close();
}
}
4.异步模式的聊天室
服务端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace UnityNetworkPractice
{
class Program
{
static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();
static void Main(string[] args)
{
Socket listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEp = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
listenfd.Bind(ipEp);
listenfd.Listen(0);
Console.WriteLine("服务器启动");
//异步
listenfd.BeginAccept(AcceptCallback, listenfd);
Console.ReadKey();
//同步
//Socket connfd = listenfd.Accept();
//while (true)
//{
// byte[] readBuff = new byte[1024];
// int count = connfd.Receive(readBuff);
// string readStr = Encoding.UTF8.GetString(readBuff, 0, count);
// Console.WriteLine("服务器接收:" + readStr);
// byte[] sendBytes = Encoding.UTF8.GetBytes(readStr);
// connfd.Send(sendBytes);
//}
}
private static void AcceptCallback(IAsyncResult ar)
{
try
{
Console.WriteLine("一个客户端连接");
Socket listenfd = (Socket)ar.AsyncState;
Socket clientfd = listenfd.EndAccept(ar);
//clients列表
ClientState state = new ClientState();
state.socket = clientfd;
clients.Add(clientfd, state);
//接收客户端数据
clientfd.BeginReceive(state.readBuff, 0, 1024, 0, ReceiveCallback, state);
//继续Accept客户端
listenfd.BeginAccept(AcceptCallback, listenfd);
}
catch(SocketException e)
{
Console.WriteLine("接收客户端失败:" + e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
ClientState state = (ClientState)ar.AsyncState;
Socket clientfd = state.socket;
int count = clientfd.EndReceive(ar);
//客户端关闭
if(count==0)
{
clientfd.Close();
clients.Remove(clientfd);
Console.WriteLine("客户端关闭");
return;
}
string recvStr = Encoding.UTF8.GetString(state.readBuff, 0, count);
string reomteIP = ((IPEndPoint)clientfd.RemoteEndPoint).Address.ToString();
Console.WriteLine(reomteIP + ":" + recvStr);
string sendStr = clientfd.RemoteEndPoint.ToString() + ":" + recvStr;
byte[] sendBytes = Encoding.UTF8.GetBytes(sendStr);
foreach(ClientState s in clients.Values)
{
s.socket.Send(sendBytes);
}
clientfd.BeginReceive(state.readBuff, 0, 1024, 0, ReceiveCallback, state);
}
catch (SocketException e)
{
Console.WriteLine("接收客户端数据失败:" + e.ToString());
}
}
}
class ClientState
{
public Socket socket;
public byte[] readBuff = new byte[1024];
}
}
客户端
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
public class Echo : MonoBehaviour
{
Socket socket;
public InputField input;
public Text text;
byte[] readBuffer = new byte[1024];
string recvStr = "";
public void ConnectBtn()
{
socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
socket.BeginConnect("127.0.0.1", 8888, ConnectCallback, socket);
//socket.Connect("127.0.0.1", 8888);
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket socket = (Socket)ar.AsyncState;
socket.EndConnect(ar);
Debug.Log("连接成功");
socket.BeginReceive(readBuffer, 0, 1024, 0, ReceiveCallback, socket);
}
catch(SocketException e)
{
Debug.Log("连接失败:" + e.ToString());
}
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
Socket socket = (Socket)ar.AsyncState;
int count = socket.EndReceive(ar);
string s = Encoding.UTF8.GetString(readBuffer, 0, count);
recvStr = s + "\n" + recvStr;
socket.BeginReceive(readBuffer, 0, 1024, 0, ReceiveCallback, socket);
}
catch(SocketException e)
{
Debug.Log("接收失败:" + e.ToString());
}
}
public void SendBtn()
{
//同步
//Send
//string sendStr = input.text;
//byte[] sendBytes = Encoding.UTF8.GetBytes(sendStr);
//for (int i = 0; i < 100000; i++)
//{
// socket.Send(sendBytes);//由于缓冲区大小有限,所以当使用同步Send快速发送大量数据时,可能会导致缓冲区被阻塞,从而使得发送数据是被卡住
//}
//Receive
//byte[] readBuff = new byte[1024];
//int count = socket.Receive(readBuff);
//string recvStr = Encoding.UTF8.GetString(readBuff, 0, count);
//socket.Close();
//异步
string sendStr = input.text;
byte[] sendBytes = Encoding.UTF8.GetBytes(sendStr);
socket.BeginSend(sendBytes, 0, sendBytes.Length, 0, SendCallback, socket);//异步不会卡住
}
private void SendCallback(IAsyncResult ar)
{
try
{
Socket socket = (Socket)ar.AsyncState;
int count = socket.EndSend(ar);
Debug.Log("发送成功:" + count);
}
catch(SocketException e)
{
Debug.Log("发送失败:" + e.ToString());
}
}
private void Update()
{
text.text = recvStr;
}
}