java Socket编程

一,网络编程中两个主要的问题

一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输。

TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机。

TCP层则提供面向应用的可靠(tcp)的或非可靠(UDP)的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。

目前较为流行的网络编程模型是客户机/服务器(C/S)结构。即通信双方一方作为服务器等待客户提出请求并予以响应。客户则在需要服务时向服务器提 出申请。服务器一般作为守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客户,同时自己继续监听服务端口,使后来的客户也 能及时得到服务。

二,两类传输协议:TCPUDP

TCPTranfer Control Protocol 简称,是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建 立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送 或接收操作。

UDPUser Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。

比较:

UDP1,每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。

            2,UDP传输数据时是大小限制的,每个被传输的数据报必须限定在64KB之内

           3,UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方

TCP1,面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中需要连接

                时间。

            2,TCP传输数据大小限制,一旦连接建立起来,双方的socket就可以按统一的格式传输的  

                    数据。

             3,TCP是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据。

应用:

1,TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。但是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽,因此TCP传输的效率不如UDP

2,UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。例如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。

三,Socket编程

在网络的双向链路当中,Socket可以表示链路当中的一端(服务器端或者客户端),通过Socket就可以进行两端的通信了。在一般的编程当中服务器端一般是用ServerSocket,客户端一般是用Socket.

从JAVA的API中了解一下Socket:

Socket的几种构造方法:

    

 
Socket() 
          通过系统默认类型的 SocketImpl 创建未连接套接字
 
Socket(InetAddress address, int port) 
          创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
 
Socket(InetAddress host, int port, boolean stream) 
          已过时。 Use DatagramSocket instead for UDP transport.
 
Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 
          创建一个套接字并将其连接到指定远程地址上的指定远程端口。
 
Socket(Proxy proxy) 
          创建一个未连接的套接字并指定代理类型(如果有),该代理不管其他设置如何都应被使用。
protected Socket(SocketImpl impl) 
          使用用户指定的 SocketImpl 创建一个未连接 Socket。
 
Socket(String host, int port) 
          创建一个流套接字并将其连接到指定主机上的指定端口号。
 
Socket(String host, int port, boolean stream) 
          已过时。 使用 DatagramSocket 取代 UDP 传输。
 
Socket(String host, int port, InetAddress localAddr, int localPort) 
          创建一个套接字并将其连接到指定远程主机上的指定远程端口。

Socket的简单用法:

    Socket socket = new Socket("服务器IP" , "服务器端口号");这样就简单的像服务器发送请求了

    如果请求通过了,通过socket来从服务器获取相应的输入流或则设置相应的输出流给服务器即可

ServerSocket的API解释:

 

相关构造方法:

ServerSocket() 
          创建非绑定服务器套接字。
ServerSocket(int port) 
          创建绑定到特定端口的服务器套接字。
ServerSocket(int port, int backlog) 
          利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
ServerSocket(int port, int backlog, InetAddress bindAddr) 
          使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。

对ServerSocket中一些常用方法:

   accept()   该方法监听客户端Socket的请求,请求通过后返回一个Socket(这个Socket不是客户端的Socket,而只是用于和客户端Socket进行对接的Socket)

    做个如下比喻:

    ServerSocket是一个公司,请求的Socket是客户,当客户去公司请求相关服务的时候,来到前台说明来意后,前台小妹妹就(accept)确认后你的信息后,

就安排了一个业务员(accept返回的Socket)来与你洽谈,业务员将相关服务数据给客户的话是要用业务员的OutPutStream ,而客户给业务员的数据对业务员

来说是InputStream , 对客户来说是OutputStream.所以说serverSocket和Socket之间是不直接进行通信的,而是ServerSocket的代表Socket和客户端

的Socket进行通信的

    ServerSocket简单用法:

    ServerSocket ss = new ServerSocket(port); port端口号一般要设置大于1023

注意,在选择端口时,必须小心。每一个端口提供一种特定的服务,只有给出正确的端口,才 能获得相应的服务。0~1023的端口号为系统所保留,例如http服务的端口号为80,telnet服务的端口号为21,

ftp服务的端口号为23, 所以我们在选择端口号时,最好选择一个大于1023的数以防止发生冲突。

     Socket serventSocket = ss.accept();

    在进行相应的数据流处理

下面通过一个简单的demo说明Socket ,

    服务器端(创建一个java工程):

 

 1 public class ServerSocketTest {
 2 
 3     public static void main(String[] args) {
 4 
 5         try {
 6             ServerSocket ss = new ServerSocket(8081);
 7             // 采用while循环是保证服务器一直开启
 8             while (true) {
 9                 System.out.println("ServerSocketTest");
10                 Socket s = ss.accept();
11                 OutputStream os = s.getOutputStream();
12                 String str = "aaaaaaaaaaaaaaaaa";
13                 byte[] bData = str.getBytes("utf-8");
14                 os.write(bData);
15                 os.close();
16                 s.close();
17             }
18 
19         } catch (IOException e) {
20             e.printStackTrace();
21         }
22 
23     }
24 }

 

上面的代码运行后你查看任务管理器当中有一条这个:

   

表示服务正在运行 , 如果你没有加while循环去重复监听客户端的请求,那么在请求一次过后,红框范围的服务进行就会消息了,后续的请求就不会有相应了    

 

Android客户端(点击一个Button,打印出服务器返回来的数据):

 1 public class MainActivity extends Activity {
 2 
 3     private TextView tvTextView;
 4     private Button btn;
 5 
 6     @Override
 7     protected void onCreate(Bundle savedInstanceState) {
 8         super.onCreate(savedInstanceState);
 9         setContentView(R.layout.activity_main);
10 
11         tvTextView = (TextView) findViewById(R.id.tv_show);
12         btn = (Button) findViewById(R.id.btn);
13         btn.setOnClickListener(new OnClickListener() {
14 
15             @Override
16             public void onClick(View v) {
17                 new Thread() {
18                     @Override
19                     public void run() {
20                         try {
21                             Socket socket = new Socket("222.18.162.132", 8081);
22                             BufferedReader bufferedReader = new BufferedReader(
23                                     new InputStreamReader(socket
24                                             .getInputStream()));
25 
26                             OutputStream os = socket.getOutputStream();
27                             byte[] bStr = "client".getBytes("utf-8");
28                             os.write(bStr);
29                             String str = bufferedReader.readLine();
30                             System.out.println("传过来的数据->" + str);
31                             socket.close();
32                             bufferedReader.close();
33                             os.close();
34 
35                         } catch (UnknownHostException e) {
36                             e.printStackTrace();
37                         } catch (IOException e) {
38                             e.printStackTrace();
39                         }
40 
41                     }
42 
43                 }.start();
44 
45             }
46         });
47 
48     }
49 
50 }

打印出来的结果是:

 

posted @ 2015-06-03 19:16  perfect亮  阅读(187)  评论(0)    收藏  举报