c#(Socket搭建TCP协议实现网络通信)

c#

  • 写在前面:前俩天学了c#的Socket搭建TCP网络通信,反手和坐在背后的彬彬hxd萌生了连一手通讯的想法,于是他java,我c#开始了操作,第一天我们一个c#,一个java成功一对一局域网通信连上了,第二天,想升个级,做一个服务端,做一堆客户端,客户端连接上服务端后可以给其他客户端发送消息。
    于是说干就干,第二天我做了简易的服务端和客户端,勉强可以多个客户端互相通话了,好了我的故事就此打住了,但彬彬没有完,现在是第三天,他把项目写的更完备,部署到了自己的服务器上,拿到他的程序和服务器ip,就可以登入这家伙的小型通话软件。虽然没什么实际作用,不过姑且算是给刚入手Socket编程的我练了练手,于是记录一些操作。

c#编写Socket之服务端

  • 创建一个Socket
static Socket serverSocket;
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//这三个参数的意思分别是使用IP4地址,使用数据流传输数据,使用Wcp协议
  • 为一个Socket绑定IP和端口
//创建IPAddress绑定IP地址
IPAddress ipAddress = IPAddress.Parse("192.168.43.109");    //这边我放的我局域网ip
//创建IpEndPoint绑定IPAddress和端口号
IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 8000);
//给Socket绑定IP和端口号
serverSocket.Bind(ipEndPoint);
  • 让一个绑定了ip和端口号的Socket作为服务器端来监听接收客户端的连接
//开始监听端口号,0表示不限制同时处理的上限,有数字表示同时处理的上限为多少
serverSocket.Listen(1);
//接收一个客户端连接,一个线程在这里会停顿,直到有客户端连接过来,得到这个客户端的Socket
Socket clientSocket = serverSocket.Accept();
  • 当接受了一个客户端的连接后,使用该客户端的Socket的BeginReceive方法来接受其发来的消息
static byte[] dataBuffer = new byte[1024];
clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
//第一个参数是一个字节型数组,用来作为消息缓存区
//第二个参数是这个缓存区从第几位开始用
//第三个参数是这个缓存区总共有多长可以用
//第四个参数我暂时也不清楚到底是做什么用的,姑且就这样填着吧(有大佬知道还请指正一下)
//第五个参数是回调函数,就是当这条线程跑完之后调用的函数(调用ReginReceive会开启一个新的线程)
//第六个参数随便传什么都可以,回调函数可以通过固定的IAsyncResult参数来取得第六个参数,为了取得该线程的返回值,我选择了传递客户端Socket
  • 接收消息用的回调函数,这个函数有个固定的IAsyncResult参数,别问问就固定。
    这个函数中调用的 ar.AsyncState as Socket;这句话是调用IAsyncResult参数的AsyncState方法,来取得之前BenginReceive方法的第六个参数,由于当时我传的客户端socket所以这边直接将其转换为Socket型的对象,存下来,就是客户端的Socket
    这个函数用了clientSocket.EndReceive(IasyncResult a);方法,调用客户端socket的这个方法,并把这条线程对应的IAsyncResult参数传进去可以取得这条线程的返回值,这里的返回值是接收到的这条数据的字节数,可以用来翻译字节数据。
    另外我写了字符串数据翻译的格式是:以’$'开头,那么这条消息是给当前客户端改名,以其他数据开头,中间用 ‘ $’隔开后面再接一条数据,意味着给某人发某消息,符号前是人的名字,符号后是消息
    方法实现如下
void ReceiveCallBack(IAsyncResult ar)
        {
            //接受的数据转成字符串
            Socket clientSocket = ar.AsyncState as Socket;
            int count = clientSocket.EndReceive(ar);
            string msg = Encoding.UTF8.GetString(dataBuffer, 0, count);

            if(msg[0]=='$')
            {
                Console.WriteLine("客户端{0}更名为:{1}", this.Name, msg.Substring(1));
                Name = msg.Substring(1);
                clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
                return;
            }


            //字符串拆解成目标用户和内容
            string name = "";
            for(int i = 0;i<msg.Length;i++)
            {
                if(msg[i]=='$')
                {
                    name = msg.Substring(0, i);
                    msg = msg.Substring(i + 1);
                    break;
                }
            }
            if(name=="")
            {
                //格式不对 骂他
                GoMsg("连个消息都不会发,打车滚吧,傻逼");
            }
            else
            {
                //格式正确 勉强帮他发一下
                Program.GoMsg(name, msg, this);//这是我写的一个服务器端类的一个方法,后面我会把代码贴出来
            }
            Console.WriteLine("从客户端{0}接收到数据:" + msg,this.Name);
            clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
        }
  • 除了接收消息,服务器还要把客户端的消息转发给对应的客户端
public void GoMsg(string msg)
{
	//这是位于服务器端的客户端类的一个方法
     //给这条线程所管的用户发一条消息msg,要将字符串先按照UTF8的格式转化为字节流
     clientSocket.Send(Encoding.UTF8.GetBytes(msg));
}
static public void GoMsg(string name,string msg,Client cl)
        {
        	//位于服务器类的发信方法
            //发信息的函数
            int i = 0;
            for (;i< ClientNum;i++)
            {
                if(Client[i].Name==name)
                {
                    break;
                }
            }
            if(i == ClientNum)
            {
                //遍历完之后仍然找不到这个人,骂他!
                cl.GoMsg("没这个人,你发你马呢");
            }
            else
            {
                msg = cl.Name +"对你说:"+ msg;
                Client[i].GoMsg(msg);
            }
        }//发信函数

c#编写Socket之客户端

  • 首先我们得有一个Socket对象,绑定好服务器的ip和端口,去连接它,方法和服务器那边差的不多,就是多用了一个连接方法Connect(IPEndPoint i),这个Socket对象里的方法是与参数i绑定的ip和端口所指的服务器做连接,代码如下
Console.WriteLine("请输入目标服务器的端口");
            ip = Console.ReadLine();
            dk = int.Parse(ip);
            Console.WriteLine("请输入目标服务器的ip");
            ip = Console.ReadLine();
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //与服务器端建立连接
            clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ip), dk));
  • 接收服务器发来的消息,方法与服务器那边接受客户端的消息差不多,不过更简单,由于服务器已经对消息进行了解析,整合,所以这边什么都不需要做,直接接受,翻译,打印即可
//开新的线程专门用来无限接受消息
clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
static byte[] dataBuffer = new byte[1024];
static void ReceiveCallBack(IAsyncResult ar)
        {
            Socket clientSocket = ar.AsyncState as Socket;
            int count = clientSocket.EndReceive(ar);
            string msg = Encoding.UTF8.GetString(dataBuffer, 0, count);
            Console.WriteLine(msg);
            clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
        }
  • 客户端给服务器发消息就粗暴了很多,直接在主线程一手死循环,无限发就行(没有跳出,没有断开连接,别学(装傻))
while (true)
            {
                string s = Console.ReadLine();
                clientSocket.Send(Encoding.UTF8.GetBytes(s));
            }

c#编写Socket总源码

  • 服务器端的服务器类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading.Tasks;
using System.Threading;

namespace 与彬彬的Socket
{
    class Program
    {
        static Socket serverSocket;
        static Client[] Client = new Client[100];
        static int ClientNum = 0;
        static void Main(string[] args)
        {
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //创建IPAddress绑定IP地址
            IPAddress ipAddress = IPAddress.Parse("192.168.43.109");
            //创建IpEndPoint绑定IPAddress和端口号
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 8000);
            //给Socket绑定IP和端口号
            serverSocket.Bind(ipEndPoint);
            AddClientSocket();
        }
        static public void AddClientSocket()
        {
            //启动一个新的客户端线程
            Client s = new Client("用户"+ClientNum, serverSocket);
            Client[ClientNum] = s;
            Thread th = new Thread(s.Socket_Client);
            th.Start();
            ClientNum++;
        }
        static public void GoMsg(string name,string msg,Client cl)
        {
            //发信息的函数
            int i = 0;
            for (;i< ClientNum;i++)
            {
                if(Client[i].Name==name)
                {
                    break;
                }
            }
            if(i == ClientNum)
            {
                //遍历完之后仍然找不到这个人,骂他!
                cl.GoMsg("没这个人,你发你马呢");
            }
            else
            {
                msg = cl.Name +"对你说:"+ msg;
                Client[i].GoMsg(msg);
            }
        }//发信函数
        static byte[] dataBuffer = new byte[1024];
        static void ReceiveCallBack(IAsyncResult ar)
        {
            Socket clientSocket = ar.AsyncState as Socket;
            int count = clientSocket.EndReceive(ar);
            string msg = Encoding.UTF8.GetString(dataBuffer, 0, count);
            Console.WriteLine("从客户端接收到数据:" + msg);
            clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
        }
    }
}

  • 服务器端的客户端类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading.Tasks;

namespace 与彬彬的Socket
{
    class Client
    {
        Socket serverSocket;
        Socket clientSocket;
        public string Name = "";
        public Client(string name, Socket serverSocket)
        {
            Name = name;
            this.serverSocket = serverSocket;
        } 
        public void GoMsg(string msg)
        {
            //给这条线程所管的用户发一条消息msg
            clientSocket.Send(Encoding.UTF8.GetBytes(msg));
        }
        public void Socket_Client()
        {
            StartServerAsync(serverSocket);
        }
        private void StartServerAsync(Socket serverSocket)
        {
            //开始监听端口号,0表示不限制同时处理的上限,有数字表示同时处理的上限为多少
            serverSocket.Listen(1);
            //接收一个客户端连接
            Socket clientSocket = serverSocket.Accept();
            this.clientSocket = clientSocket;
            GoMsg("你好,你是:" + Name);


            //再让服务端启动一份客户端线程
            Program.AddClientSocket();

            //接受客户端的一条消息
            clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
        }//异步接收数据,并递归
        byte[] dataBuffer = new byte[1024];
        void ReceiveCallBack(IAsyncResult ar)
        {
            //接受的数据转成字符串
            Socket clientSocket = ar.AsyncState as Socket;
            int count = clientSocket.EndReceive(ar);
            string msg = Encoding.UTF8.GetString(dataBuffer, 0, count);

            if(msg[0]=='$')
            {
                Console.WriteLine("客户端{0}更名为:{1}", this.Name, msg.Substring(1));
                Name = msg.Substring(1);
                clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
                return;
            }


            //字符串拆解成目标用户和内容
            string name = "";
            for(int i = 0;i<msg.Length;i++)
            {
                if(msg[i]=='$')
                {
                    name = msg.Substring(0, i);
                    msg = msg.Substring(i + 1);
                    break;
                }
            }
            if(name=="")
            {
                //格式不对 骂他
                GoMsg("连个消息都不会发,打车滚吧,傻逼");
            }
            else
            {
                //格式正确 勉强帮他发一下
                Program.GoMsg(name, msg, this);
            }
            Console.WriteLine("从客户端{0}接收到数据:" + msg,this.Name);
            clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
        }
    }
}

  • 客户端那边的类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading.Tasks;
using System.Threading;

namespace 与彬彬的Socket客户端
{
    class Program
    {
        static string ip;
        static int dk;
        static void Main(string[] args)
        {
            Console.WriteLine("请输入目标服务器的端口");
            ip = Console.ReadLine();
            dk = int.Parse(ip);
            Console.WriteLine("请输入目标服务器的ip");
            ip = Console.ReadLine();
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //与服务器端建立连接
            clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ip), dk));
            clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
            while (true)
            {
                string s = Console.ReadLine();
                clientSocket.Send(Encoding.UTF8.GetBytes(s));
            }
        }
        static byte[] dataBuffer = new byte[1024];
        static void ReceiveCallBack(IAsyncResult ar)
        {
            Socket clientSocket = ar.AsyncState as Socket;
            int count = clientSocket.EndReceive(ar);
            string msg = Encoding.UTF8.GetString(dataBuffer, 0, count);
            Console.WriteLine(msg);
            clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
        }
    }
}

  • 如此这般 结束(三个源码分俩个项目生成后就可以在局域网用辣!)

你可能感兴趣的:(编程语言学习,socket,网络协议,网络通信,网络,c#)