zoukankan      html  css  js  c++  java
  • Socket套接字:客户端与服务端进行通信

    客户端与服务端进行通信的协议是Tcp/Ip,我们客户端与服务端实现数据通信除了协议的支持外,还需要一个Socket套接字的应用。下面我将我学习Socket的的这个例子:实现客户端与服务端通信,来给大家一看分享学习一下: 第一:这是WinForm环境下的,首先是一个布局,客户端和服务端各一个WinForm。 第二:客户端要想连接服务端,首先我得有一个IP,得有一个端口号,所以我服务端可以这样来安排,由于是本地练习,所以IP固定为:127.0.0.1 端口号固定为:5000,这里我可以开始写我的监听事件了,首先我创建一个Socket套接字WatchSocket,用创建好的套接字去关联IP、端口,并绑定,设置监听队列。具体服务端设置监听的代码如下:

    Socket WatchSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
    IPAddress ipAddress = IPAddress.Parse(txtIP.Text); IPEndPoint endPoint = new IPEndPoint(ipAddress, Convert.ToInt32(txtDK.Text)); 
    WatchSocket.Bind(endPoint); 
    WatchSocket.Listen(10);

    其中,Socket参数分别代表:寻址协议,以流的方式传输,采用TCP协议。 而下面绑定的比如,txtIP 、 txtDK 则代表WinForm中相对于的属性Name,不多解释。 到这里,我们服务端绑定了Socket之后,客户端呢,客户端同样也需要连接服务端,这样两者才能达到连接与被连接状态,具体客户端连接代码如下:

    Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
     IPAddress ipAddress = IPAddress.Parse(txtIP.Text); IPEndPoint endPoint = new IPEndPoint(ipAddress, Convert.ToInt32(txtDK.Text));
     clientSocket.Connect(endPoint);

    是不是感觉客户端Socket连接与服务端Socket创建都差不多,对的,就是这样。只不过一个是连接,一个是监听。 写到这里,读者可以延伸一下,给一些更醒目的提示,在这里就不说了。 第三:客户端与服务端连接成功后,就应该交互数据了,那么我们首先来看看客户端向服务端发送数据 同样,WinForm界面上的处理也是给他一个文本框用于存储数据,一个按钮用于发送时触发,我首先需要获取发送的内容,然后将内容转换成byte字节的形式发送,发送成功后,清空文本框内容,代码如下:

    string str = txtSend.Text; byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str); clientSocket.Send(buffer); txtSend.Text = "";

    是不是代码很简单呢,这个时候,我客户端的数据就已经发送到服务端了,服务端当然得接收了,让我们一起来看看服务端是怎么接收客户端发送过来的数据的。接收是用的Accept,由于接收时会涉及到多线程的问题,并且接收状态为While(true){ } 表示我随时在接收,但是,接收时,总得找个地方吧,同样,在服务端接收数据时也需要创建一个byte数组,给他一个内存空间,比如1M,由于我传过来的是字节流形式,那么我服务端首先需要用Receive接收到客户端发送过来的字节流数据,将其存入缓冲区,然后将其转换成String类型,显示到界面上,具体接收代码如下:

    byte[] buffer = new byte[1024 * 1024]; string msg = System.Text.Encoding.UTF8.GetString(buffer);

    是不是感觉代码很简单呀,只要知道了这个思路,代码其实没什么难的。 第四:既然客户端可以向服务端发送数据,那么服务端同样也可以向客户端发送数据,道理一样,就不单独说了,这里我们说一下服务端向多个客户端群发数据。 首先服务端向多个客户端群发,无非就是让多个客户端连接上服务端,服务端获取这些客户端的IP和端口号,然后遍历发送,IP我们用的是本地固定的,端口号更不用说了,一般我们要超过1024以免重复。思路分享如下:在一个ListBox里面通过集合获取连接的多个客户端,将每个客户端的IP显示到服务端的ListBox集合里面。由于每个客户端连接是都是通过Socket绑定IP和端口来实现,所以可以用一个Dictionary集合来把绑定的IP、端口,Socket给获取。如:

    Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
     while(true)
     {
    Socket newSocket = WatchSocket.Accept(); dicSocket.Add(newSocket.RemoteEndPoint.ToString(), newSocket); txtLsb.Items.Add(newSocket.RemoteEndPoint.ToString()); 
    }

    这样,我就把每个客户端给获取到了,群发时无非就是就是遍历循环ListBox,然后发送,代码如下:

    string msg = txtSendAll.Text; 
    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(msg); foreach (string item in txtLsb.Items)
     { 
    dicSocket[item].Send(buffer); 
    } 
    txtSendAll.Text = "";

    同理,客户端接收时,也是先在内存中找一个地方,然后把接收到的字节流转换成字符串给显示到界面,代码如下:

    byte[] buffer = new byte[1024 * 1024];
     int recLength = clientSocket.Receive(buffer); 
    string msg = System.Text.Encoding.UTF8.GetString(buffer, 0, recLength);

    这个时候群发搞定。 第五:上述只是写到了字符串的发过来发过去,我现在想要发一个文件怎么办,应该怎么做呢,让我们一起来看一下,从客户端发送一个文件到服务端。 首先,界面上的得有一个打开文件的按钮,一个发送文件的按钮,一个现实发送文件名字的一个Text; 其次,打开文件用OpenFileDialog ,获取文件名称将其显示到Text中,这个就不多说了。 然后,是发送文件,同样我也是把文件转换到一个字节数组里面,将字节流发送过去,用到了FileStream,代码分享如下:

    byte[] buffer = new byte[1024 * 1024]; 
    using (FileStream fs = new FileStream(this.txtSendFile.Text, FileMode.Open)) 
    { 
    int readLength = fs.Read(buffer, 0, buffer.Length); byte[] newBuffer = new byte[readLength + 1];
     newBuffer[0] = 1;
     Buffer.BlockCopy(buffer, 0, newBuffer, 1, readLength); clientSocket.Send(newBuffer); 
    }

    其中我把这个字节数组又给创建了一个newBuffer,目的是为了服务端接收文件的时候,区分出来到底接收的是字符串还是文件,其中把第一个字节赋值为1表示文件。 那么服务端开始接收客户端发送过来的文件了,发送成功,开始接收之前,需要创建一个另存为对话框,SaveFileDialog,代码如下:

    SaveFileDialog sf = new SaveFileDialog(); 
    if (DialogResult.OK == sf.ShowDialog())//弹出一个另存为对话框 
    { 
    string fileName = sf.FileName; 
    using (FileStream fs = new FileStream(fileName, FileMode.Create)) //写入磁盘 
    {
     fs.Write(buffer, 1, recLength - 1);
     } 
    }

    此时,整个客户端与服务端的通信就到这了。 其中有两个地方没有花力气去说,

    第一:多线程时,要在窗口构造函数中,把微软的这个TextBox.CheckForIllegalCrossThreadCalls = false;设置一下。

    第二:涉及到多线程问题时,比如,客户端发送数据,服务端接收数据等,会碰到单线程不能反应的问题,这个时候用多线程控制可以解决,关于多线程的问题,会单独列出来分享。

    这里主要把Socket实现客户端与服务端通信给介绍一下。希望大家多多指点,一起学习。

  • 相关阅读:
    CDH 2、Cloudera Manager的安装
    204 01 Android 零基础入门 03 Java常用工具类 04 Java集合 04 Map集合 01 Map概述
    203 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 07 删除宠物猫信息数据(引入泛型知识点)
    202 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 06 查找宠物猫信息数据
    201 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 05 添加重复的宠物猫信息数据
    200 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 04 添加和显式宠物猫信息
    199 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 03 宠物猫信息管理概述
    198 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 02 案例:在集合中插入字符串
    197 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 01 Set概述
    196 01 Android 零基础入门 03 Java常用工具类 04 Java集合 02 List集合 05 案例:公告的删除和修改
  • 原文地址:https://www.cnblogs.com/duanshunjie/p/3293560.html
Copyright © 2011-2022 走看看