您的位置:首页 > 其它

SOCKET通信的基本步骤

2014-07-22 22:40 232 查看


SOCKET通信的基本步骤

1)建立一个服务器ServerSocket,并同时定义好ServerSocket的监听端口;

2)ServerSocket 调用accept()方法,使之处于阻塞。

3)创建一个客户机Socket,并设置好服务器的IP和端口。

4)客户机发出连接请求,建立连接。

5)分别取得服务器和客户端ServerSocket 和Socket的InputStream和OutputStream.

6) 利用Socket和ServerSocket进行数据通信。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式:

同步:

所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是必须一件一件事做,等前一件做完了才能做下一件事。

例如普通B/S模式(同步):提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事

异步:

异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。

例如
ajax请求(异步): 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕

阻塞

阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,cpu不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果之后才会返回。

有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。 例如,我们在socket中调用recv函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息。

非阻塞

非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

对象的阻塞模式和阻塞函数调用

对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。阻塞对象上可以有非阻塞的调用方式,我们可以通过一定的API去轮询状 态,在适当的时候调用阻塞函数,就可以避免阻塞。而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。

1. 同步,就是我调用一个功能,该功能没有结束前,我死等结果。

2. 异步,就是我调用一个功能,不需要知道该功能结果,该功能有结果后通知我(回调通知)

3. 阻塞, 就是调用我(函数),我(函数)没有接收完数据或者没有得到结果之前,我不会返回。

4. 非阻塞, 就是调用我(函数),我(函数)立即返回,通过select通知调用者

同步IO和异步IO的区别就在于:数据拷贝的时候进程是否阻塞!

阻塞IO和非阻塞IO的区别就在于:应用程序的调用是否立即返回!

对于举个简单c/s 模式:

同步:提交请求->等待服务器处理->处理完毕返回这个期间客户端浏览器不能干任何事

异步:请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕

同步和异步都只针对于本机SOCKET而言的。

同步和异步,阻塞和非阻塞,有些混用,其实它们完全不是一回事,而且它们修饰的对象也不相同。

阻塞和非阻塞是指当进程访问的数据如果尚未就绪,进程是否需要等待,简单说这相当于函数内部的实现区别,也就是未就绪时是直接返回还是等待就绪;
而同步和异步是指访问数据的机制,同步一般指主动请求并等待I/O操作完毕的方式,当数据就绪后在读写的时候必须阻塞(区别就绪与读写二个阶段,同步的读写必须阻塞),异步则指主动请求数据后便可以继续处理其它任务,随后等待I/O,操作完毕的通知,这可以使进程在数据读写时也不阻塞。(等待"通知")

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
客户端:
综合运用以上阐述的使用Visual C#进行Socket网络程序开发的知识,下面的程序段完整地实现了Web页面下载功能。用户只需在窗体上输入远程主机名(Dns 主机名或以点分隔的四部分表示法格式的 IP 地址)和预保存的本地文件名,并利用专门提供Http服务的80端口,就可以获取远程主机页面并保存在本地机指定文件中。如果保存格式是.htm格式,你就可以在Internet浏览器中打开该页面。适当添加代码,你甚至可以实现一个简单的浏览器程序。



实现此功能的主要源代码如下:

//"开始"按钮事件

private void button1_Click(object sender, System.EventArgs e)
{

//取得预保存的文件名

string fileName=textBox3.Text.Trim();

//远程主机

string hostName=textBox1.Text.Trim();

//端口

int port=Int32.Parse(textBox2.Text.Trim());

//得到主机信息

IPHostEntry ipInfo=Dns.GetHostByName(hostName);

//取得IPAddress[]

IPAddress[] ipAddr=ipInfo.AddressList;

//得到ip

IPAddress ip=ipAddr[0];

//组合出远程终结点

IPEndPoint hostEP=new IPEndPoint(ip,port);

//创建Socket 实例

Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

try

{

//尝试连接

socket.Connect(hostEP);

}

catch(Exception se)

{

MessageBox.Show("连接错误"+se.Message,"提示信息

,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);

}

//发送给远程主机的请求内容串

string sendStr="GET / HTTP/1.1\r\nHost: " + hostName +

"\r\nConnection: Close\r\n\r\n";

//创建bytes字节数组以转换发送串

byte[] bytesSendStr=new byte[1024];

//将发送内容字符串转换成字节byte数组

bytesSendStr=Encoding.ASCII.GetBytes(sendStr);

try

{

//向主机发送请求

socket.Send(bytesSendStr,bytesSendStr.Length,0);

}

catch(Exception ce)

{

MessageBox.Show("发送错误:"+ce.Message,"提示信息

,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);

}

//声明接收返回内容的字符串

string recvStr="";

//声明字节数组,一次接收数据的长度为1024字节

byte[] recvBytes=new byte[1024];

//返回实际接收内容的字节数

int bytes=0;

//循环读取,直到接收完所有数据

while(true)

{

bytes=socket.Receive(recvBytes,recvBytes.Length,0);

//读取完成后退出循环

if(bytes<=0)

break;

//将读取的字节数转换为字符串

recvStr+=Encoding.ASCII.GetString(recvBytes,0,bytes);

}

//将所读取的字符串转换为字节数组

byte[] content=Encoding.ASCII.GetBytes(recvStr);

try

{

//创建文件流对象实例

FileStream fs=new FileStream(fileName,FileMode.OpenOrCreate,FileAccess.ReadWrite);

//写入文件

fs.Write(content,0,content.Length);

}

catch(Exception fe)

{

MessageBox.Show("文件创建/写入错误:"+fe.Message,"提示信息",MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);

}

//禁用Socket

socket.Shutdown(SocketShutdown.Both);

//关闭Socket

socket.Close();

}

}

//////////////////////////////////////////////////////////////////////////////////////////////
/client端

using System;

using System.Text;

using System.IO;

using System.Net;

using System.Net.Sockets;

namespace socketsample

{

 class Class1

 {

  static void Main()

  {

   try

   {

    int port = 2000;

    string host = "127.0.0.1";

    IPAddress ip = IPAddress.Parse(host);

    IPEndPoint ipe = new IPEndPoint(ip, port);

    Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    c.Connect(ipe);

    string sendStr = "hello!This is a socket test";

    byte[] bs = Encoding.ASCII.GetBytes(sendStr);

    c.Send(bs, bs.Length, 0);

    string recvStr = "";

    byte[] recvBytes = new byte[1024];

    int bytes;

    bytes = c.Receive(recvBytes, recvBytes.Length, 0);

    recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);

    Console.WriteLine(recvStr);

    c.Close();

   }

   catch (ArgumentNullException e)

   {

    Console.WriteLine("ArgumentNullException: {0}", e);

   }

   catch (SocketException e)

   {

    Console.WriteLine("SocketException: {0}", e);

   }

   Console.ReadLine();

  }

 }

}

//server端

using System;

using System.Text;

using System.IO;

using System.Net;

using System.Net.Sockets;

namespace Project1

{

 class Class2

 {

  static void Main()

  {

   try

   {

    int port = 2000;

    string host = "127.0.0.1";

    IPAddress ip = IPAddress.Parse(host);

    IPEndPoint ipe = new IPEndPoint(ip, port);

    Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    s.Bind(ipe);

    s.Listen(0);

    Socket temp = s.Accept();

    string recvStr = "";

    byte[] recvBytes = new byte[1024];

    int bytes;

    bytes = temp.Receive(recvBytes, recvBytes.Length, 0);

    recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);

    Console.WriteLine(recvStr);

    string sendStr = "Ok!Sucess!";

    byte[] bs = Encoding.ASCII.GetBytes(sendStr);

    temp.Send(bs, bs.Length, 0);

    temp.Shutdown(SocketShutdown.Both);

    temp.Close();

    s.Shutdown(SocketShutdown.Both);

    s.Close();

   }

   catch (ArgumentNullException e)

   {

    Console.WriteLine("ArgumentNullException: {0}", e);

   }

   catch (SocketException e)

   {

    Console.WriteLine("SocketException: {0}", e);

   }

   Console.ReadLine();

  }

 }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: