服务端
先做个同步的
// 这种通常用于socket的复制
public Socket(SocketInformation socketInformation);
// 后面两种通常用于新创建的socket
public Socket(SocketType socketType, ProtocolType protocolType);
//指定 Socket 类的实例可以使用的寻址方案(通常IPv4 也有IPv6) Socket类的实例表示的套接字类型 指定 Socket 类支持的协议
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);
搭配不当就出异常
常用组合
// Udp通信
Socket socket = new Socket(SocketType.Dgram, ProtocolType.Udp);
// Tcp通信
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
用VS窗口控制台
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace TalkRoomTCP
{
class Program
{
static void Main(string[] args)
{
//创建socket using 代替Close 用完不关闭会占用端口
using (Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp))
{
//绑定IP 端口号
//IPAddress.Any:相当于"0.0.0.0"的IP地址侦听本地所有网络接口上的客户端活动 有几个侦听几个
//IPAddress.Broadcast:相当于"255.255.255.255"的IP地址,通常用于Udp的数据包广播。
//IPAddress.Loopback:相当于"127.0.0.1"的IP地址,用于指代本机。监听"127.0.0.1"时,只能从本机连接到服务端。
socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999));
//开启监听 参数是最大接受队列的长度 多于这个就只响应100个 其他拒绝
socket.Listen(100);
//accept客户端同步连接 如果客户端不连接,服务器程序阻塞(挂起)这个位置
using (var clientSocket = socket.Accept())
{
//客户端接收消息 如果客户端不发送数据 服务器程序阻塞(挂起)这个位置
var buffer = new byte[1024];
int length = clientSocket.Receive(buffer);
Console.WriteLine($"接收到客户端消息:{Encoding.UTF8.GetString(buffer)}");
//接受的消息再发回去
clientSocket.Send(buffer);
}
}
// 接收一个键盘输入的字符,目的是不让命令行自动关闭
Console.ReadKey();
}
}
}
客户端
unity创建个项目
/**
*Copyright(C) 2019 by #COMPANY#
*All rights reserved.
*FileName: #SCRIPTFULLNAME#
*Author: #AUTHOR#
*Version: #VERSION#
*UnityVersion:#UNITYVERSION#
*Date: #DATE#
*Description:
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class TalkClient : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
//连接服务器
socket.Connect("127.0.0.1", 9999);
//发送数据
socket.Send(Encoding.UTF8.GetBytes("你好"));
//接受数据
var buffer = new byte[1024];
int length = socket.Receive(buffer);
print(Encoding.UTF8.GetString(buffer));
}
}
先运行服务器 再拖动脚本到物体上运行启动客户端
image.pngimage.png
然后客户端改个界面
image.png
text差不多大就行
/**
*Copyright(C) 2019 by #COMPANY#
*All rights reserved.
*FileName: #SCRIPTFULLNAME#
*Author: #AUTHOR#
*Version: #VERSION#
*UnityVersion:#UNITYVERSION#
*Date: #DATE#
*Description:
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine.UI;
public class TalkClient : MonoBehaviour
{
public InputField input;
public Text text;
public Button btn;
byte[] buffer = new byte[1024];
Socket socket;
// Start is called before the first frame update
void Start()
{
socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
//连接服务器
socket.Connect("127.0.0.1", 9999);
btn.onClick.AddListener(Send);
}
void Send()
{
//发送数据
socket.Send(Encoding.UTF8.GetBytes(input.text));
//接受数据
int length = socket.Receive(buffer);
text.text += Encoding.UTF8.GetString(buffer, 0, length) + "\n";
}
}
image.png
改为异步服务器
一般项目都是源源不断请求的
所以要开线程异步完成
socket封装的有方便我们写了
先升级服务端
每次Accept 或者Receive 关闭之后都要重新调用
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace TalkRoomTCP
{
class Program
{
static void Main(string[] args)
{
//创建socket using 代替Close 用完不关闭会占用端口
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
//绑定IP 端口号
//IPAddress.Any:相当于"0.0.0.0"的IP地址侦听本地所有网络接口上的客户端活动 有几个侦听几个
//IPAddress.Broadcast:相当于"255.255.255.255"的IP地址,通常用于Udp的数据包广播。
//IPAddress.Loopback:相当于"127.0.0.1"的IP地址,用于指代本机。监听"127.0.0.1"时,只能从本机连接到服务端。
socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999));
//开启监听 参数是最大接受队列的长度 多于这个就只响应100个 其他拒绝
socket.Listen(100);
//开启异步 第二个参数用于传递一些数据
socket.BeginAccept(AcceptCallBack, socket);
Console.WriteLine("服务器启动");
// 接收一个键盘输入的字符,目的是不让命令行自动关闭
Console.ReadKey();
}
private static void AcceptCallBack(IAsyncResult ar)
{
var socket = ar.AsyncState as Socket;
var clientSocket = socket.EndAccept(ar);
Console.WriteLine($"{clientSocket.RemoteEndPoint}客户端连接");
//客户端接收消息 如果客户端不发送数据 服务器程序阻塞(挂起)这个位置
var buffer = new byte[1024];
clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallBack, (clientSocket, buffer));
int length = clientSocket.Receive(buffer);
// 递归继续Accept
socket.BeginAccept(AcceptCallBack, socket);
}
private static void ReceiveCallBack(IAsyncResult ar)
{
//这种是元组 匿名的结构体
//这里的buffer数组只在新连接进来的时候,给每个新连接创建了一次,
//后续与客户端通信的socket会绑定这个buffer数据,
//通过复用这个buffer可以减少内存的申请和释放,提高性能。
(var clientSocket, var buffer) = ((Socket, byte[]))ar.AsyncState;
int length = clientSocket.EndReceive(ar);
//小于0客户端就关闭了
if (length>0)
{
Console.WriteLine($"接收到客户端的消息:{Encoding.UTF8.GetString(buffer, 0, length)}");
clientSocket.Send(buffer, length, SocketFlags.None);
//递归重新开始接收
clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallBack, (clientSocket, buffer));
}
else
{
Console.WriteLine($"{clientSocket.RemoteEndPoint}断开连接");
clientSocket.Close();
}
}
}
}
网友评论