客户端与服务端进行通讯的协议是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,而后发送,代码以下:this
string msg = txtSendAll.Text; byte[] buffer = System.Text.Encoding.UTF8.GetBytes(msg); foreach (string item in txtLsb.Items) { dicSocket[item].Send(buffer); } txtSendAll.Text = "";
同理,客户端接收时,也是先在内存中找一个地方,而后把接收到的字节流转换成字符串给显示到界面,代码以下:spa
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,代码以下:code
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); } }
此时,整个客户端与服务端的通讯就到这了。 其中有两个地方没有花力气去说,orm
第一:多线程时,要在窗口构造函数中,把微软的这个TextBox.CheckForIllegalCrossThreadCalls = false;设置一下。
第二:涉及到多线程问题时,好比,客户端发送数据,服务端接收数据等,会碰到单线程不能反应的问题,这个时候用多线程控制能够解决,关于多线程的问题,会单独列出来分享。
这里主要把Socket实现客户端与服务端通讯给介绍一下。但愿你们多多指点,一块儿学习。