C#Socket客户端和服务器端编写

最近在做个多人游戏的demo,试试自己编写服务器端,在写之前,就不介绍Tcp和Udp的区别了,网上资料很多,在看socket编程之前最好先去看看基础的Tcp和Udp的理论内容,再去看Socket编程会好很多。

C#的socket编程主要用到一下命名空间:

  1. System.Net;//socket的重要基础
  2.  System.Net.Sockets;//socket的重要基础
  3. System.Text;//因为socket只能发送byte数组,也只能接收byte数组,需要把接收到的byte数组转化为字符串
  4. System.Threading;//主要用来开启一个负责监听和接收消息的线程

socket的常用类和方法

  相关类:

  1.    IPAddress:包含了一个IP地址
  2.    IPEndPoint:包含了一对IP地址和端口号

相关方法 

  1.    Socket():创建一个Socket
  2.    Bind():绑定一个本地的IP和端口号(IPEndPoint)
  3.    Listen():让Socket侦听传入的连接吃那个病,并指定侦听队列容量
  4.    Connect():初始化与另一个Socket的连接
  5.    Accept():接收连接并返回一个新的Socket
  6.    Send():输出数据到Socket,只能发送一个byte数组
  7.    Receive():从Socket中读取数据,返回接收到的数据的长度
  8.    Close():关闭Socket,销毁连接

 客户端和服务器端结构如图

客户端与服务器结构图

       

 

通过上图,我们可以看出,首先服务器会创建一个负责监听的socket,然后客户端通过socket连接到服务器指定端口,最后服务器端负责监听的socket,监听到客户端有连接过来了,就创建一个负责和客户端通信的socket。

下面我们来看下Socket更具体的通信过程:

Socket的通讯过程

  服务器端:

    01,申请一个socket

    02,绑定到一个IP地址和一个端口上

    03,开启侦听,等待接收连接

  客户端:

    01,申请一个socket

   02,连接服务器(指明IP地址和端口号)

   服务器端接收到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并进行通信,原监听socket继续监听。

  注意:负责通信的Socket不能无限创建,创建的数量和操作系统有关。

Socket的构造函数

    Public Socket(AddressFamily addressFamily,SocketType  socketType,ProtocolType  protocolTYpe)

    AddressFamily:指定Socket用来解析地址的寻址方案。例如:InterNetWork指示当Socket使用一个IP版本4地址连接

   SocketType:定义要打开的Socket的类型

   Socket类使用ProtocolType枚举向Windows  Sockets  API通知所请求的协议

示例

IPAddress addr = IPAddress.Parse("127.0.0.1");

/*

注意如果addr是指定ip地址,那么就只能在同一个ip下进行通信,如果作为服务器端的话addr必须是IpAddress.any,

表示任意ip都可以在指定端口下访问服务器

*/

IPEndPoint endp = new IPEndPoint(addr,,9000);

         服务端先绑定:serverWelcomeSocket.Bind(endp)

         客户端再连接:clientSocket.Connect(endp)

注意

   1,一个Socket一次只能连接一台主机

   2,Socket关闭后无法再次使用

   3,每个Socket对象只能与一台远程主机连接。如果你想连接到多台远程主机,你必须创建多个Socket对象。

 

服务器端代码

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

namespace Server {
    class Program {

        //记录通信用的scoket的字典
        static Dictionary<string, Socket> sockets = new Dictionary<string, Socket> ();
        static void Main (string[] args) {
            //设置ip和端口
            IPAddress ipAddress = IPAddress.Any;
            int port = 30001;
            //绑定本机的IP和端口
            IPEndPoint endPoint = new IPEndPoint (ipAddress, port);
            //新建socket
            Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //绑定服务器的监听Socket
            try {
                socket.Bind (endPoint);
                //设置最大连接数
                socket.Listen (10); //如果是0表示不限制连接数
                ShowMessage ("开始监听");

                // 后台线程用于监听来连接上来的客户端
                Thread t = new Thread (AcceptInfo);
                t.IsBackground = true;
                t.Start (socket);

            } catch (Exception e) {
                // 打印错误信息
                ShowMessage (e.Message);
            }

            Console.ReadKey ();
        }

        //打印信息
        static void ShowMessage (string msg) {
            Console.WriteLine (msg);
        }

        //创建链接成功后用于通信的Socket
        static void AcceptInfo (Object o) {
            Socket socket = o as Socket;

            while (true) {

                try {
                    //通信用的socket,根据连接过来的scoket返回一个新的用于通信的socket
                    Socket tSocket = socket.Accept ();
                    string point = tSocket.RemoteEndPoint.ToString ();
                    //把通信socket加入字典
                    sockets.Add (point, tSocket);
                    ShowMessage (point + " 连接成功");
                    //接收客户端的信息
                    Thread t = new Thread (ReceiveMsg);
                    t.IsBackground = true;
                    t.Start (tSocket);

                } catch (Exception e) {
                    ShowMessage (e.Message);
                    break;
                }
            }

        }

        static void ReceiveMsg (Object o) {
            Socket client = o as Socket;

            while (true) {
                try {
                    byte[] buffer = new byte[1024 * 1024];
                    // 获得实际接受的数据的长度
                    int n = client.Receive (buffer);
                    // 如果是一个有内容的请求
                    if (n > 0) {
                        GetRequestByCode (buffer[0], buffer, n);
                    }
                    // string words = Encoding.UTF8.GetString(buffer,0,n);
                    // ShowMessage(client.RemoteEndPoint.ToString() + ":" + words);    

                } catch (Exception e) {
                    ShowMessage (e.Message);
                    break;
                }

            }
        }

        /// <summary>
        /// 根据请求的code来获得对应的请求,即buffer[0] = code
        /// </summary>
        /// <param name="code">请求的code</param>
        /// <param name="buffer">请求的内容</param>
        /// <param name="length">实际请求内容的长度</param>
        static void GetRequestByCode (byte code, byte[] buffer, int length) {
            switch (code) {
                case 0:
                    GetRequestContent (buffer, length);
                    break;
                case 1:
                    GetRequestContent (buffer, length);
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 负责获取请求的内容
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="length"></param>
        static void GetRequestContent (byte[] buffer, int length) {
            //因为指定了buffer[0]是请求的code区分是哪个请求,请求内容从1开始
            string words = Encoding.UTF8.GetString (buffer, 1, length);
            Console.WriteLine (words);
        }

    }
}

客户端代码

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace Client {
    class Program {
        static Socket client = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        static void Main (string[] args) {
            IPAddress ip = IPAddress.Parse ("39.107.234.74");
            IPEndPoint point = new IPEndPoint (ip, 30001);

            //开始连接到服务器
            try {
                client.Connect (point);
                ShowMessage ("服务器" + client.RemoteEndPoint.ToString ());
                ShowMessage ("客户端" + client.LocalEndPoint.ToString ());
                SendMessage (client, 0, "我是" + client.LocalEndPoint.ToString () + "请求0过来了");
                // SendMessage(client,1,"我是" + client.LocalEndPoint.ToString() + "请求1过来了");
            } catch (Exception e) {
                ShowMessage (e.Message);
            }

            Console.ReadKey ();
        }

        static void ShowMessage (string msg) {
            Console.WriteLine (msg);
        }

        /// <summary>
        /// 发送请求(code存在byte[]的0,content存在byte[]0后面的空间里)
        /// </summary>
        /// <param name="client">发送请求的socket</param>
        /// <param name="requestCode">请求的编码</param>
        /// <param name="context">请求的内容</param>
        static void SendMessage (Socket client, byte requestCode, string context) {
            if (client != null && client.Connected) {
                try {
                    byte[] buffer = Encoding.UTF8.GetBytes (context);
                    //新的请求格式buffer[0]是请求的编码,buffe后面的内容是请求的内容
                    List<byte> list = new List<byte> ();
                    list.Add (requestCode);
                    list.AddRange (buffer);
                    byte[] newbuffer = list.ToArray ();
                    client.Send (newbuffer);
                } catch (Exception e) {

                    ShowMessage (e.Message);
                }
            }
        }
    }
}

至此结束。

 

 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值