需要做成聊天室小Demo主要是利用Socket异步接收数据来完成的,主要是下面两个方法:
Socket.BeginAccept 方法
开始一个异步操作以接受传入的连接尝试。
System_CAPS_pubmethod BeginAccept(AsyncCallback, Object)
开始一个异步操作以接受传入的连接尝试。
System_CAPS_pubmethod BeginAccept(Int32, AsyncCallback, Object)
开始异步操作以接受传入的连接尝试并接收第一个客户端应用程序所发送的数据块。
System_CAPS_pubmethod BeginAccept(Socket, Int32, AsyncCallback, Object)
开始异步操作以接受传入的连接尝试从指定的套接字并接收第一个客户端应用程序所发送的数据块。
异步开始连接客户端,就是可以同时连接多个客户端。
Socket.BeginReceive 方法
开始异步接收数据从连接 Socket。
System_CAPS_pubmethod BeginReceive(Byte[](数据存储的位置), Int32(偏移量,即开始接收数据的起始位置), Int32(接收数据的最大位置), SocketFlags(socket标志), AsyncCallback(回调函数), Object(传入回调函数的方法))
开始异步接收数据从连接 Socket。
异步开始接收客户端发来的数据
客户端代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
//TCP的服务器端socket基本流程socket->bind->listen->accept->send/recv->closesocket
//客户端基本流程socket->[bind->]->connect->send/recv->closesocket
namespace 客户端
{
class Program
{
static void Main(string[] args)
{
startClientAsync();
}
//同步接收
static void startClientSync()
{
//创建客户端
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//与服务器进行连接
clientSocket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10086));
//接受来自服务器的消息
byte[] dataBuff = new byte[1024];
//如果没有接收,程序会执行到这等待接收,然后再往下执行
int count = clientSocket.Receive(dataBuff);
string msg = System.Text.Encoding.UTF8.GetString(dataBuff, 0, count);
Console.WriteLine("接收到来自服务器的消息" + msg);
//向服务器发送消息
while (true)
{
string msgSend = Console.ReadLine();
if (msgSend == "c")
{
clientSocket.Close();
return;
}
byte[] data = System.Text.Encoding.UTF8.GetBytes(msgSend);
clientSocket.Send(data);
}
Console.ReadKey();
//关闭客户端
clientSocket.Close();
}
//异步接收
static void startClientAsync()
{
//创建客户端
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//与服务器进行连接
clientSocket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10086));
/* //接受来自服务器的消息
byte[] dataBuff = new byte[1024];
//如果没有接收,程序会执行到这等待接收,然后再往下执行
int count = clientSocket.Receive(dataBuff);
string msg = System.Text.Encoding.UTF8.GetString(dataBuff, 0, count);
Console.WriteLine("接收到来自服务器的消息" + msg);
*/
//开始异步接受服务端发来的数据
clientSocket.BeginReceive(dataBuff,0,1024,SocketFlags.None,ReceiveCallBack,clientSocket);
//向服务器发送消息
while (true)
{
string msgSend = Console.ReadLine();
if (msgSend == "c")
{
clientSocket.Close();
return;
}
byte[] data = System.Text.Encoding.UTF8.GetBytes(msgSend);
clientSocket.Send(data);
}
Console.ReadKey();
//关闭客户端
clientSocket.Close();
}
static byte[] dataBuff = new byte[1024];
static void ReceiveCallBack(IAsyncResult ar)
{
Socket clientSocket = ar.AsyncState as Socket;
int count=clientSocket.EndReceive(ar);
string msg = Encoding.UTF8.GetString(dataBuff,0,count);
Console.WriteLine("从服务器端接收到的数据: " + msg);
clientSocket.BeginReceive(dataBuff, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
}
}
}
服务器端代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
//TCP的服务器端socket基本流程socket->bind->listen->accept->send/recv->closesocket
//客户端基本流程socket->[bind->]->connect->send/recv->closesocket
namespace TCP服务器端
{
class Programjin
{
static void Main(string[] args)
{
startServerAsync();
}
/*异步接收*/
static void startServerAsync()
{
//创建一个服务器端
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//指定IP地址
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
//分配端口号
IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 10086);
//绑定IP地址和端口号
serverSocket.Bind(ipEndPoint);
//监听端口 参数表示处理连接的队列,0表示不限制
serverSocket.Listen(0);
/*异步接收多个客户端连接*/
//方法内两个参数同样是回调函数和传入回调函数的参数
serverSocket.BeginAccept(AcceptCallBack,serverSocket);
//为了不使程序运行完后停止
while (true)
{
}
}
static byte[] dataBuff = new byte[1024];
//接受多个客户端连接的回调函数
static void AcceptCallBack(IAsyncResult ar)
{
Socket serverSocket = ar.AsyncState as Socket;
Socket clientSocket = serverSocket.EndAccept(ar);
/*向客户端发送一个数据*/
string msg = "Hello client!你好";
//将数据转化为为字节,因为数据的发送是字节的形式
byte[] date = System.Text.Encoding.UTF8.GetBytes(msg);
//在创建的连接上发送数据回去
clientSocket.Send(date);
/*服务端开始异步接收客户端发来的数据*/
//数据存储的位置 偏移(存储的开始位置) 接收数据最大的大小 Socket标志 回调函数(接收数据执行的方法) 传入回调函数的参数(等于ar.AsyncState 需强制转化为你传入参数的类型)
clientSocket.BeginReceive(dataBuff, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
serverSocket.BeginAccept(AcceptCallBack, serverSocket);
while (true)
{
string ms = Console.ReadLine();
//将数据转化为为字节,因为数据的发送是字节的形式
byte[] dat = System.Text.Encoding.UTF8.GetBytes(ms);
clientSocket.Send(dat);
Console.ReadKey();
}
}
//接收客户端发来的消息的回调函数
static void ReceiveCallBack(IAsyncResult ar)
{
Socket clientSocket = null;
try
{
clientSocket = ar.AsyncState as Socket;
int count = clientSocket.EndReceive(ar);
if (count==0)
{
clientSocket.Close();
return;
}
string msg = Encoding.UTF8.GetString(dataBuff, 0, count);
Console.WriteLine("从客户端接收到的数据: " + msg);
clientSocket.BeginReceive(dataBuff, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
}
catch (Exception e)
{
//输出异常信息
Console.WriteLine(e);
//如果一条客户端不为空
if (clientSocket!=null)
{
clientSocket.Close();
}
}
}
}
}
运行图片如下:
好了,接下来会记下如何解决TCP中的粘包,分包问题与解决方案。