计算机网络中实现通信不需要有一些约定即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等指定标准。为了使两个结点之间能进行对话,必须在他们之间建立通信工具(即接口),使彼此之间能进行信息交换。
接口包括两部分:
1.硬件装置:实现节点之间的信息传送。
2.软件装置:规定双方进行通信的约定协议。
为什么要分层:
由于节点之间的联系很复杂,在制订协议时,把复杂的成分分解成一些简单的成分,再将他们复合起来。最常用的的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展。
通信协议的分层规定:
把用户应用程序作为最高层,把物理通信线路作为最底层,将其间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准。
OSI参考模型:
应用层---->表示层---->会话层---->传输层---->网络层---->数据链路层---->物理层
TCP/IP参考模型:
应用层---->传输层---->网络层---->物理+数据链路层
IP协议是网际层的主要协议,支持网间互联的数据报通信。它提供的主要功能有:
1.无连接数据报传送
2.数据报路由选择和差错控制
Socket:
两个Java应用程序可通过一个双向的网络通信连接实现数据交换,这个双向链路的一段称为一个Socket。Socket通常用来实现client-server连接。java.net包中定义的两个类Socket和ServerSocket,分别用来实现双向连接的client和server端。建立连接时所需的寻址信息为远程计算机的IP地址和端口号(port number)。TCP、UDP的端口是分开的,各有65536个。
是专门设计用于在不可靠的因特网上提供可靠的、端到端的字节流通信协议。它是一种面向连接的协议。TCP连接是字节流而非报文流。
例子1:
import java.net.*; import java.io.*; public class TCPServer { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(6666); while(true) { Socket s = ss.accept(); System.out.println("a client connect!"); DataInputStream dis = new DataInputStream(s.getInputStream()); System.out.println(dis.readUTF()); dis.close(); s.close(); } } } import java.net.*; import java.io.*; public class TCPClient { public static void main(String[] args) throws Exception { Socket s = new Socket("127.0.0.1", 6666); OutputStream os = s.getOutputStream(); DataOutputStream dos = new DataOutputStream(os); Thread.sleep(30000); dos.writeUTF("hello server!"); dos.flush(); dos.close(); s.close(); } }
例子2:
import java.io.*; import java.net.*; public class talkclient { public static void main(String args[]) { try { Socket socket = new Socket("127.0.0.1",4700); BufferedReader sin = new BufferedReader(new InputStreamReader(System.in)); //从键盘中读取 PrintWriter os = new PrintWriter(socket.getOutputStream()); //输出到服务器端 BufferedReader is = new BufferedReader(new InputStreamReader( //从服务器端读取 socket.getInputStream())); String readline; readline = sin.readLine(); while (!readline.equals("bye")) { os.println(readline); os.flush(); System.out.println("Client:" + readline); System.out.println("Server:" + is.readLine()); readline = sin.readLine(); } os.close(); is.close(); socket.close(); }catch(Exception e) { System.out.println("Error" + e); } } } import java.io.*; import java.net.*; public class talkserver { public static void main(String args[]) { try { ServerSocket server = null; try { server = new ServerSocket(4700); }catch(Exception e) { System.out.println("can not listen to:" + e); } Socket socket = null; try { socket = server.accept(); }catch(Exception e) { System.out.println("Error:" + e); } String line; BufferedReader is = new BufferedReader(new InputStreamReader( //从客户端读取 socket.getInputStream())); PrintWriter os = new PrintWriter(socket.getOutputStream()); //输出到客户端 BufferedReader sin = new BufferedReader(new InputStreamReader(System.in)); //从键盘中读取 System.out.println("Client:" + is.readLine()); line = sin.readLine(); while (!line.equals("bye")) { os.println(line); os.flush(); System.out.println("Server:" + line); System.out.println("Client:" + is.readLine()); line = sin.readLine(); } is.close(); os.close(); socket.close(); server.close(); }catch(Exception e) { System.out.println("Error" + e); } } }
UDP想应用程序提供了一种发送封装的原始IP数据报的方式,并且发送时无需建立连接,是一种不可靠的连接。
import java.net.*; import java.io.*; public class TestUDPClient { public static void main(String args[]) throws Exception { long n = 10000L; ByteArrayOutputStream baos = new ByteArrayOutputStream(); //自动会生成一个字节数组 DataOutputStream dos = new DataOutputStream(baos); dos.writeLong(n); //通过流向字节数组写入一个Long类型的数 byte[] buf = baos.toByteArray(); //得到baos指向的字节数组 System.out.println(buf.length); DatagramPacket dp = new DatagramPacket(buf, buf.length, //利用该字节数组构造一个数据报 new InetSocketAddress("127.0.0.1", 5678) //发送的目的地址 ); DatagramSocket ds = new DatagramSocket(9999); //构建一个套接字,监听在9999端口 ds.send(dp); //通过此套接字发送数据报 ds.close(); } } import java.net.*; import java.io.*; public class TestUDPServer { public static void main(String args[]) throws Exception { byte buf[] = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, buf.length); //将数据报内容与字节数组关联 DatagramSocket ds = new DatagramSocket(5678); while(true) { ds.receive(dp); //通过套接字接收数据报并关联到dp ByteArrayInputStream bais = new ByteArrayInputStream(buf); //读入字节数组的内容 DataInputStream dis = new DataInputStream(bais); System.out.println(dis.readLong()); } } }
要特别注意字节数组的作用。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class TCPserver { public static void main(String args[]) throws IOException{ ServerSocket ss = new ServerSocket(6666); Socket s = ss.accept(); System.out.print("连接成功!"); InputStreamReader isr = new InputStreamReader(s.getInputStream()); System.out.print((char)isr.read()); //read一次读一个字符 isr.close(); } } import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.Socket; public class TCPClient { public static void main(String args[]) throws IOException{ Socket s = new Socket("127.0.0.1",6666); OutputStreamWriter os = new OutputStreamWriter(s.getOutputStream()); os.write("wuenqiang"); //os.close(); //假如我们将关闭语句注释掉,则字符串在缓冲区中,并没有被刷进流中,所以读写的时候会出错 } }
字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件,关闭时会自动刷出。
原文:http://www.cnblogs.com/mosquito-woo/p/3921849.html