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实现客户端与服务端通信给介绍一下。希望大家多多指点,一起学习。

posted @ 2013-08-31 21:56  MiccNet  阅读(804)  评论(0编辑  收藏  举报