Server和Client是一对好朋友,有一天Client想知道知道现在几点了就给Server打电话(emmmm就是想他了的意思)

Client把他的手机卡clientfd插到手机卡槽里,拨出了Server的手机号(ip+port):

//连接
Socket clientfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientfd .Connect("192.168.196.157", 2000);

但是Server积极拒绝了Client,可能Server没有开机。

Server终于开机了,他在等电话,除此之外什么都不想做(Accpet()是堵塞方法,接收客户端的连接,返回一个连接上的Socket对象,才继续往下执行):

//监听套接字
Socket listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定ip和port
IPAddress ipadr = IPAddress.Parse("192.168.196.157");
IPEndPoint ipep = new IPEndPoint(ipadr, 2000);
listenfd.Bind(ipep);
//监听,0表示不限制连接个数
listenfd.Listen(0);
//等待连接
Socket clientfd = listenfd.Accept();

开心的是,Client又试着给Server打电话,这次接通了。然后Client问现在几点了:

//发送数据
sendstr = "现在几点了" + '\r';
byte[] sendbuff = System.Text.Encoding.Default.GetBytes(sendstr);
clientfd.Send(sendbuff);

Server听完了Client的问题后,看了看时间告诉了Client:

//接收数据
int count = clientfd.Receive(readbuff);
readstr = System.Text.Encoding.Default.GetString(readbuff, 0, count);
Console.WriteLine("Client::"+readstr);

//反馈
sendstr = "Server:现在是 "+System.DateTime.Now.ToShortTimeString();
Console.WriteLine(sendstr);
sendbuff = System.Text.Encoding.Default.GetBytes(sendstr);
clientfd.Send(sendbuff);

Socket实现TCP通信:一、TCP协议下Socket如何工作的(C#实现)

。。。。。正经分割。。。。。。。。

Server端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace SyncServer
{
    class Program
    {
        static Socket listenfd;
        static Socket toclientfd;
        static byte[] readbuff = new byte[1024];
        static byte[] sendbuff = new byte[1024];
        static int count;
        static String readstr = "";
        static String sendstr = "";

        static void Main(string[] args)
        {
            //套接字
            listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //绑定
            IPAddress ipadr = IPAddress.Parse("192.168.196.157");
            IPEndPoint ipep = new IPEndPoint(ipadr, 2000);
            listenfd.Bind(ipep);
            //监听
            listenfd.Listen(0);
            Console.WriteLine("Server已开机(服务器启动成功)");
            toclientfd = listenfd.Accept();
            Console.WriteLine("接了Client的电话(服务器同意连接)");
            while (true)
            {
                count = toclientfd.Receive(readbuff);
                readstr = System.Text.Encoding.Default.GetString(readbuff, 0, count);
                Console.WriteLine(readstr);
                sendstr = "Server:现在是 "+System.DateTime.Now.ToShortTimeString();
                Console.WriteLine(sendstr);
                sendbuff = System.Text.Encoding.Default.GetBytes(sendstr);
                toclientfd.Send(sendbuff);
            }

        }
    }
}

Client端:

using System;
using System.Net.Sockets;
using System.Windows.Forms;

namespace SyncClient
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        string sendstr = "";
        string readstr = "";
        Socket socket;
        byte[] readBuff = new byte[1024];

        private void Conn_btn_Click(object sender, EventArgs e)
        {
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect("192.168.196.157", 2000);
            Dialog.Items.Add("Server接电话啦(服务器已连接)");
        }

        private void Send_btn_Click(object sender, EventArgs e)
        {
            sendstr = "Client:" + textBox1.Text + '\r';
            byte[] sendbuff = System.Text.Encoding.Default.GetBytes(sendstr);
            socket.Send(sendbuff);
            Dialog.Items.Add( sendstr);
            int count = socket.Receive(readBuff);
            readstr = System.Text.Encoding.Default.GetString(readBuff, 0, count);
            Dialog.Items.Add(readstr);
        }
    }
}

。。。。。正经分割。。。。。。。。

但是,Client发现有时候Server不接电话,自己只能一直打一直打(Connect()是阻塞方法),有时候自己说错了,赶快重新说一次,但是Server愣住了没有反应(Receive()是阻塞方法),有时候别人跟Server聊着天,自己就只能等他们聊完,Server也不喜欢一直守着电话(Accept()是阻塞方法)、等别人说话回复别人卡死(Send()是阻塞方法)的感觉,于是他们换了一种打电话的方式。

Server开好机后,做些别的时间,没事看两眼有没有电话(BeginAccept(....)非阻塞方法,异步):

//套接字
Socket listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定
IPAddress ipadr = IPAddress.Parse("192.168.196.157");
IPEndPoint ipep = new IPEndPoint(ipadr, 2000);
listenfd.Bind(ipep);
//监听
listenfd.Listen(0);
listenfd.BeginAccept(AcceptCallback, listenfd);


public void AcceptCallback(IAsyncResult ar)
{
   try
   {
              
       Socket listenfd = (Socket)ar.AsyncState;
       clientfd= listenfd.EndAccept(ar);

   }catch (Exception e) {
       Console.WriteLine(e.ToString());
   }
}

Client也是,拨出(BeginConnect(...)非阻塞方法,异步)号码后把手边的东西清一清:

 private void Conn_btn_Click(object sender, EventArgs e)
        {
            clientfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //连接同一局域网
            clientfd.BeginConnect("192.168.196.157", 2000,ConnectCallback, clientfd);
        }

        public void ConnectCallback(IAsyncResult ar)
        {
            try
            {
                Socket socket = (Socket)ar.AsyncState;
                socket.EndConnect(ar);

            }catch(Exception e)
            {
                Console.WriteLine("Socket Connect fail:" + e.ToString());
            }
        }

Server接了电话后,他们开始聊天了,不用等着对方说话,有声音的话就去听,没声音的时候可以做点别的。

clientfd.BeginReceive(readBuff, 0, 1024, 0, ReceiveCallback, clientfd);
clientfd.BeginSend(sendBuff)


public  void ReceiveCallback(IAsyncResult ar)
{
    try
    {
        Socket socket = (Socket)ar.AsyncState;
        int count = socket.EndReceive(ar);
       
        string readstr = System.Text.Encoding.Default.GetString(readBuff, 0, count);
                socket.BeginReceive(readBuff, 0, 1024, 0, ReceiveCallback, socket);

    }catch (Exception e)
    {
        Console.WriteLine("Socket Reveive fail: " + e.ToString());
    }
}


public void SendCallback(IAsyncResult ar)
{
    try
    {
        Socket socket = (Socket)ar.AsyncState;
        socket.EndSend(ar);
    }catch(Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

 

Socket实现TCP通信:一、TCP协议下Socket如何工作的(C#实现)

。。。。。正经分割。。。。。。。。

Server端:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EchoServer
{
    public partial class ServerWin : Form
    {
        public ServerWin()
        {
            InitializeComponent();
        }

        Socket listenfd;
        Socket clientfd;
        byte[] readBuff = new byte[1024];
        byte[] sendbuff = new byte[1024];

        private void Listen_btn_Click(object sender, EventArgs e)
        {
            //套接字
            listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //绑定
            IPAddress ipadr = IPAddress.Parse("192.168.196.157");
            IPEndPoint ipep = new IPEndPoint(ipadr, 2000);
            listenfd.Bind(ipep);
            //监听
            listenfd.Listen(0);
            Dialog.Items.Add("Server已开机(服务器启动成功)");
            listenfd.BeginAccept(AcceptCallback, listenfd);

        }

        private void Send_btn_Click(object sender, EventArgs e)
        {
            byte[] sendbuff = System.Text.Encoding.Default.GetBytes(textBox1.Text);
            clientfd.BeginSend(sendbuff,0,sendbuff.Length,0,SendCallback, clientfd);
            SetProgressDelegate setprogress = new SetProgressDelegate(SetProgress);
            this.Invoke(setprogress, new object[] { "Server:"+ textBox1.Text, "" });
        }


        
        public delegate void SetProgressDelegate(String str,String name);

        public void SetProgress(String str, String name)
        {
            Dialog.Items.Add(str);
            if(name!=null)
                Online.Items.Add(name);
        }

        public void AcceptCallback(IAsyncResult ar)
        {
            try
            {
                Socket listenfd = (Socket)ar.AsyncState;
                clientfd= listenfd.EndAccept(ar);

                //  Dialog.Items.Add("Client上线啦");
                SetProgressDelegate setprogress = new SetProgressDelegate(SetProgress);
                this.Invoke(setprogress, new object[] { "Client上线啦", "Client" });

                sendbuff = System.Text.Encoding.Default.GetBytes("接了Client的电话(服务器同意连接)");
                clientfd.Send(sendbuff);
                clientfd.BeginReceive(readBuff, 0, 1024, 0, ReceiveCallback, clientfd);

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        
        public  void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                Socket socket = (Socket)ar.AsyncState;
                int count = socket.EndReceive(ar);
       
                string readstr = System.Text.Encoding.Default.GetString(readBuff, 0, count);
                //Dialog.Items.Add(name+":"+ readstr);
                SetProgressDelegate setprogress = new SetProgressDelegate(SetProgress);
                this.Invoke(setprogress, new object[] { "Client:" + readstr,"" });

                socket.BeginReceive(readBuff, 0, 1024, 0, ReceiveCallback, socket);

            }
            catch (Exception e)
            {
                Console.WriteLine("Socket Reveive fail: " + e.ToString());
            }
        }

        public void SendCallback(IAsyncResult ar)
        {
            try
            {
                Socket socket = (Socket)ar.AsyncState;
                socket.EndSend(ar);
            }catch(Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

    }
}

Client端:

using System;
using System.Net.Sockets;
using System.Windows.Forms;

namespace SyncClient
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        string sendstr = "";
        string readstr = "";
        Socket socket;
        byte[] readBuff = new byte[1024];

        private void Conn_btn_Click(object sender, EventArgs e)
        {
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect("192.168.196.157", 2000);
            Dialog.Items.Add("Server接电话啦(服务器已连接)");
        }

        private void Send_btn_Click(object sender, EventArgs e)
        {
            sendstr = "Client:" + textBox1.Text + '\r';
            byte[] sendbuff = System.Text.Encoding.Default.GetBytes(sendstr);
            socket.Send(sendbuff);
            Dialog.Items.Add( sendstr);
            int count = socket.Receive(readBuff);
            readstr = System.Text.Encoding.Default.GetString(readBuff, 0, count);
            Dialog.Items.Add(readstr);
        }
    }
}

。。。。。正经分割。。。。。。。。

现在他们可以愉快的聊天啦。

 

。。。。。。。。。。。。。。。。。。。。。正经强分割。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

怎么连接的:

Socket实现TCP通信:一、TCP协议下Socket如何工作的(C#实现)

Server端的重点(同步的方法时):

1)创建服务端的套接字, 实例初始化 System.Net.Sockets.Socket 类使用指定的地址族、 套接字类型和协议。其中AddressFamily的InterNetwork指ipv4地址,SocketType.stream指定字节流,ProtocolType.Tcp指定使用TCP协议传输。

Socket listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

2)Bind绑定地址ip和端口port

//绑定
IPAddress ipadr = IPAddress.Parse("192.168.196.157");
IPEndPoint ipep = new IPEndPoint(ipadr, 2000);
listenfd.Bind(ipep);

3)Listen开启监听,socket.Listen(backlog),backlog限定队列中最多容纳等待接收的连接数,0表示不限制

//监听
listenfd.Listen(0);

4)同意连接Accept(),属于阻塞方法,当没有客户端的连接申请时,服务端阻塞在这里,直到接收到客户的连接,返回一个客户端的socket对象。

Socket clientfd= listenfd.Accept();

5)可以看出,服务端有两种套接字,一个监听套接字,用来监听绑定的地址和端口上时候有客户端的申请连接,一个对应客户端的套接字,用于接收和发送指定对象数据。

Client端重点(同步的方法时):

1)创建客户端套接字,同服务端

Socket clientfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

2)申请连接,Connect(ip,port),属于阻塞方法,会一直卡住等待服务器接收,超时或拒绝

clientfd.Connect("192.168.196.157", 2000);

3)发送数据Send,接收数据Receive,都属于阻塞方法

clientfd.Send(sendBuff)
clientfd.Receive(readBuff)

同步->异步

同步方法 异步方法

Accept

BeginAccept

开始一个异步操作来接收连接请求

EndAccept

异步连接

Connect

BeginConnect

开始一个异步操作来申请连接

EndConnect

结束挂起的异步连接请求

Receive

BeginReceive

开始一个异步操作来接收数据

EndReceive

将数据异步发送到连接套接字

Send

BeginSend

开始一个异步操作来发送数据

EndSend

结束挂起的异步发送

 

异步的核心接口:IAsyncResult

#region 程序集 mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\mscorlib.dll
#endregion

using System.Runtime.InteropServices;
using System.Threading;

namespace System
{
    //
    // 摘要:
    //     表示异步操作的状态。
    [ComVisible(true)]
    public interface IAsyncResult
    {
        //
        // 摘要:
        //     获取一个值,该值指示异步操作是否已完成。
        //
        // 返回结果:
        //     如果操作已完成,则为 true;否则为 false。
        bool IsCompleted { get; }
        //
        // 摘要:
        //     获取用于等待异步操作完成的 System.Threading.WaitHandle。
        //
        // 返回结果:
        //     用于等待异步操作完成的 System.Threading.WaitHandle。
        WaitHandle AsyncWaitHandle { get; }
        //
        // 摘要:
        //     获取一个用户定义的对象,该对象限定或包含有关异步操作的信息。
        //
        // 返回结果:
        //     一个用户定义的对象,限定或包含有关异步操作的信息。
        object AsyncState { get; }
        //
        // 摘要:
        //     获取一个值,该值指示异步操作是否同步完成。
        //
        // 返回结果:
        //     如果异步操作同步完成,则为 true;否则为 false。
        bool CompletedSynchronously { get; }
    }
}

实现IAsyncResult的回调方法是多线程的方法,以达到异步的目的。IAsyncResult中的AsyncState对象就是当前线程中操作的客户/服务端套接字。

委托机制 : delegate

回调方法中不能进行UI操作,上述异步例程中使用委托的方式更新UI,将异步接收的数据显示在对话框中,具体不作描述。

----------------------------------------------------------------------------------------------------------------------------------------------------------------

写在最后:花花冲鸭!

 

 

 

 

 

 

相关文章: