• Socket网络编程


    一、Socket网络编程

    1、概念:Socket    英文愿意是孔或插座。作为BSD UNIX的进程通信机制,取后一种意思,通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。

    2、理解:

    客户端如果要链接服务器,首先要知道服务器的IP地址,但服务器中有很多应用程序,光知道IP地址是不够的,因为客户端不知道链接哪一个程序,所以还需要知道一个服务器的端口号。有了服务器的IP地址和端口号,才能建立Socket连接。

    3、传输的过程中还需要一个协议,协议有两种:TCP、 UDP

    TCP特点:安全稳定,不会发生数据丢失,效率低,要求必须有一个服务器。因为要经历三次握手过程:1)客户端请求; 2)服务器响应  3)客户端得知服务器响应。 

    然后才开始传输

    UDP特点:效率高,但有可能会发生数据丢失(不稳定)。不用经过服务器响应是否有空闲接受消息,自主传输

    举例:视频聊天时,TCP肯定会很清晰,但有可能会卡,因为服务器可能会忙;而UDP不会很清晰,但不会卡,所以视频聊天一般使用UDP协议

    4、下面开始创建服务器:

    1) 创建一个负责监听的Socket对象,负责监听某个IP地址和端口号

    /当点击监听的时候,在服务器端创建一个负责监听IP地址跟端口号的Socket
    Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    2)获取本机的IP地址,并创建端口号对象,将获取的IP地址传参进去。

    IPAddress ip = IPAddress.Any; //IPAddress.Parse(txtServer.Text);
    //创建端口号
    IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
    3)设置绑定端口号,调用监听Socket对象的绑定方法,参数为前面创建的端口号对象

    //监听绑定
    socketWatch.Bind(point);
    ShowMsg("监听成功");
    4)设置监听:调用Socket的监听方法,参数是等待队列

    socketWatch.Listen(10); //等待队列
    5)创建负责通信的Socket对象,等待客户端的连接。注意:监听要写在while(true)里面,因为需要一直监听,并且需要创建后台新线程来执行它

    //等待客户端的连接,并且创建一个负责通信的Socket 它代表客户端的Socket
    Socket socketSend = socketWatch.Accept();
    //如果连接成功,将”IP+:连接成功“追加到信息显示文本框中
    ShowMsg(socketSend.RemoteEndPoint.ToString() + ":连接成功");
    这时候可以将IP地址和通信Socket存储成一个键值对集合:

    //将此次连接的Socket存入键值对集合
    dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend);

    6)连接成功后,接收客户端发过来的消息。注意:接收也要写在while(true)里面,需要一直接收客户端发过来的消息,并且需要创建后台新线程来执行它
    byte[] buffer = new byte[1024 * 1024 * 2]; //创建一个字节数组,用来接收数据
    int r = socketSend.Receive(buffer); //此方法实现接收客户端发过来的消息,并将其收入参数字节数组中,返回接收字节数
    if (r == 0)
    return;
    string str = Encoding.UTF8.GetString(buffer, 0, r); //将字节数组转回字符串
    ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + str);
    7)实现给指定客户端发送消息:

    string str = txtMsg.Text.Trim(); //获取将要发送的消息
    byte[] buffer = Encoding.UTF8.GetBytes(str); //转成字节数组
    string ip = comboBox1.SelectedItem.ToString(); //获得指定的客户端通信Socket
    dicSocket[ip].Send(buffer); //发送消息

    5、开始创建客户端
    1)创建负责通信的Socket:

    //创建负责通信的Socket
    socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    2)获取将要连接的服务器的IP和程序的端口:
    //获得要连接的服务器程序的IP地址和端口号
    IPAddress ip = IPAddress.Parse(txtServer.Text.Trim());
    IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text.Trim()));
    3)建立连接:
    socketSend.Connect(point); //建立连接
    ShowMsg("连接成功");
    4)给服务器发送消息:
    string str = txtMessage.Text.Trim(); //获取要发送的消息
    byte[] buffer = Encoding.UTF8.GetBytes(str); //转成字节数组
    socketSend.Send(buffer); //发送字节数组
    5)不停的接收服务器发来的消息:注意:接收也要写在while(true)里面,需要一直接收客户端发过来的消息,并且需要创建后台新线程来执行它
    byte[] buffer = new byte[1024 * 1024 * 2]; //定义一个字节数组
    int r = socketSend.Receive(buffer); //接收字节数组放入buffer中,返回接收的字节数
    if (r == 0) //如果没有信息接收,结束该循环
    return;
    string str = Encoding.UTF8.GetString(buffer, 0, r); //将接受的字节数组转成字符串
    ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + str); //显示出来
    //开启新线程,不停的接收服务器发来的消息
    Thread th = new Thread(Receive);
    th.IsBackground = true;
    th.Start();

    6、判断服务器发送的消息的文件格式,并区分接收。协议为: 文字消息---0; 文件----1;震动----2
    1)文字消息:

    服务器发送前添加协议

    //给buffer添加一个协议
    List<byte> list = new List<byte>();
    list.Add(0); //首位赋值0
    list.AddRange(buffer); //将buffer全部赋值给list,从第二位开始
    byte[] newBuffer = list.ToArray(); //转回字节数组,返回一个新数组
    将发送消息的参数改为新字节数组:
    dicSocket[ip].Send(newBuffer); //发送消息

    客户端接收前判断协议
    //判断协议,区分处理
    if(buffer[0]==0) //如果服务器发送的是文字消息! 注意:解码时要从第二位开始解码了,将0改为1,解码字节数-1
    {
    string str = Encoding.UTF8.GetString(buffer, 1, r-1); //将接受的字节数组转成字符串
    ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + str); //显示出来
    }

    2)文本接收、
    服务器:

    打开对话框

    OpenFileDialog open = new OpenFileDialog();
    open.InitialDirectory = @"C:Users ufeiaxDesktop";
    open.Title = "请选择要打开的文件";
    open.Filter = "文本文件|*.txt|图片文件|*.jpg|所有文件|*.*";
    open.ShowDialog();
    发送选中的文本:
    //获得要发送文件的全路径
    string path = txtPath.Text.Trim();
    //读取文件,并将其转换为字节数组
    using (FileStream fsread = new FileStream(path, FileMode.Open, FileAccess.Read))
    {
    byte[] buffer = new byte[1024 * 1024 * 5];
    int r = fsread.Read(buffer, 0, buffer.Length);

    List<byte> list = new List<byte>();
    list.Add(1);
    list.AddRange(buffer);
    byte[] newBuffer = list.ToArray();
    //注意:因为要多发一个字节,所有发送字节数为r+1
    dicSocket[comboBox1.SelectedItem.ToString()].Send(newBuffer, 0, r + 1, SocketFlags.None);
    }
    客户端:
    else if(buffer[0] ==1)
    {
    SaveFileDialog save = new SaveFileDialog();
    save.InitialDirectory = @"C:Users ufeiaxDesktop";
    save.Title = "请选择要保存的文件";
    save.Filter = "文本文件|*.txt|图片文件|*.jpg|所有文件|*.*";
    save.ShowDialog(this);
    string path = save.FileName;
    //保存文件
    using(FileStream fsWrite = new FileStream(path,FileMode.OpenOrCreate,FileAccess.Write))
    {
    fsWrite.Write(buffer, 1, r - 1);
    }
    MessageBox.Show("保存成功");
    }

    3)震动消息
    服务器:

    byte[] buffer = new byte[1];
    buffer[0] = 2;
    dicSocket[comboBox1.SelectedItem.ToString()].Send(buffer);
    客户端:
    for (int i = 0; i < 200; i++)
    {
    this.Location = new Point(200, 200);
    this.Location = new Point(250, 250);
    }



  • 相关阅读:
    【转】strlen和mb_strlen区别(php获得中英文混合字符长度)
    PHP字符串替换的相关方法介绍
    php表单转换textarea换行符的方法
    vue生命周期及其作用
    elemenui点击单行触发样式,选中或不选中复选框
    flutter 介绍和环境搭建
    flutter组件
    tora消息机制(事件监听,触发,取消)
    Promise功能与应用
    CCF CSP 20018031 跳一跳
  • 原文地址:https://www.cnblogs.com/aijiao/p/9961893.html
Copyright © 2020-2023  润新知