一、网络模型
OSI(Open System Interconnection开放系统互连)参考模型
1.物理层——这一层的数据叫比特
2.数据链路层——这一层的数据叫帧(对数据进行MAC地址,即网卡的地址进行封装与解封装)
3.网络层——对数据进行IP地址的封装与解封装,这一层数据叫数据包
4.传输层——这一层数据叫段,定义了一些传输数据的协议和端口号,对从下层传来的数据进行分段和传输
5.会话层——主要在你的系统之间发起会话或者接受会话请求
6.表示层——主要是进行对接收的数据进行解释、加密或解密、压缩与解压缩等。
7.应用层——主要是一些终端的应用。
二、网络通讯要素
1.IP地址
本地回环地址:127.0.0.1 主机名:localhost
2.端口号
有效端口:0-65535 其中0-1024系统使用或保留端口。
用于标识进程的逻辑地址,不同进程的标识。
3.传输协议
常见协议:TCP、UDP
(1)UDP
不需要建立连接,每个数据报的大小限制在64K内,因为无连接,是不可靠协议,但是速度快。
(2)TCP
需建立连接,可进行大数据量传输,通过三次握手完成连接,是可靠协议,效率低。
在java中,网络编程的包为java.net包,在INetAddress接口中封装IP地址,有两个子类INet4Address和INet6Address。
例1:
public static void oper() throws UnknownHostException { //获取取本地主机ip地址对象 InetAddress ip=InetAddress.getLocalHost(); System.out.println(ip.getHostAddress()); System.out.println(ip.getHostName()); //如何获取指定的主机的ip地址对象 ip=InetAddress.getByName("my_think"); //InetAddress.getByName("192.168.1.100);也可以 }
三、Socket
Socket就是为网络服务提供的一种机制。通信的两端都有Socket,网络通信其实就是Socket间的通信,数据就在两个Socket间通过IO传输。
DatagramSocket此类表示用来发送和接收数据报包的套接字。
DatagramPacket此类表示数据报包。
例2:UDP实例
//发送端 public static void main(String[] args) throws SocketException { /* *创建UDP传输的发送端思路: *1. 建立udp的socket服务 *2. 将要发送的数据封装到数据包中 *3. 通过udp的socket服务将数据包发送出去 *4. 关闭socket服务 */ DatagramSocket ds=new DatagramSocket(); // String str="UDP传输演示:哥们来了!";
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
String line=null;
while ((line=bufr.readLine())!=null)
{
if ("over".equals(line))
break;
byte[] buf=line.getBytes();
DatagramPacket dp=new Datagrampacket(buf,buf.length,InetAddress.getName("192.168.1.100",10000);
// byte[] buf=str.getBytes(); // DatagramPacket dp=new Datagrampacket(buf,buf.length,InetAddress.getName("192.168.1.100",10000); ds.send(dp);
ds.close(); } //接收端 public static void main(String[] args) { /* *建立UDP接收端的思路 *1. 建立udp socket服务 *2. 创建数据包,用于存储接收到的数据,方便用数据包对象的方法解析这些数据 *3. 使用socket服务的rece方法将接收到的数据存储到数据包中。 *4. 通过数据包的方未能解析数据包中的数据 *5. 关闭资源 */ DatagramSocket ds=new DatagramSocket(10000);
while(true)
{ byte[] buf=new byte[1024]; DatagramPacket dp=new DatagramPacket(buf,buf.legnth); ds.receive(dp); //阻塞式的 String ip=dp.getAddress().getHostAddress(); int port=dp.getPort(); String text=new String(dp.getdata(),0,dp.getLength()); }
ds.close();
}
例3:TCP传输
Socket和ServerSocket ,这一点和UDP不一样,UDP中DatagramSocket即可接收也可发送。
建立客户端和服务器端
建立连接后,通过Socket中的IO流进行数据的传输
最后需要关闭socket
//TCP客户端 public static void TCPClientDemo throws UnKnowHostException,IOException { /*客户端发数据到服务端 *Tcp传输,客户端建立的过程 *1. 创建tcp客户端socket服务,使用的是Socket对象,建议该对象一创建就明确目的地,要连接的主机。 *2. 如果连接建立成功,说明数据传输通道已建立。该通道就是socket流,是底层建立好的。既然是流,说明这里既有输入,又有输出。想要输入或者输出流对象,可以找socket来获取。 *可以通过getOutputStream()和getInputStream()来获取两个字节流。 *3. 使用输出流,将数据写出。 *4. 关闭资源,其实质是断开连接 */ Socket socket=new Socket("192.168.1.100",10002); OutputStream out=socket.getOutputStream(); out.write("tcp演示!");
//读取服务端返回的数据
InputStream in=socket.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf);
string text=new String(buf,0,len);
system.out.println(text); socket.close(); } //TCP服务端 public static void main(String[] args) { /* *建立tcp服务端的思路 *1. 创建服务端socket服务,通过ServerSocket对象 *2. 服务端必须对外提供一个端口,否则客户端无法连接 *3. 获取连接过来的客户端对象 *4. 通过客户端获取socket流读取客户端发来的数据,并打印在控制台上 *5. 关闭资源,需要关客户端和服务端 */ ServerSocket ss=ServerSocket(10002); Socket s=ss.accept(); //获取客户端套接字 String ip=s.getInetAddress().getHostAddress(); InputStream in=s.getInputStream(); byte[] buf=new byte[1024]; int len=in.read(buf); String text=new String(buf,0,len); system.out.println(ip+":"+text);
//使用客户端socket对象的输出流给客端返回数据
OutputStream out=s.getOutputStream();
out.write("收到"); s.close(); ss.close(); }
在上传文件时,为了告诉服务器,客户端写完了。可添加:
socket.shutdownOutput();
服务器端因为accept阻塞,所以在一个客户处理完成之前,其他客户必须等待。可以用多线程解决:
public static void main(String [] args) throws IOException { ServerSocket ss=new ServerSocket(10006); while(true) { Socket s=ss.accept(); //以下多线程执行 new Thread(new UploadTask(s)).start(); } } //创建UploadTaskod类 public class UploadTask implements Runnable { private Socket s; public UploadTask(Socket s){ this.s=s; } @override public void run() { String ip=s.getInetAddress().getHostAddress(); System.out.println(ip+"....connected"); try{ InputStream in=s.getInputStream(); File dir=new File("c:\pic"); if (!dir.exist()){ dir.mkdirs(); } File file=new File(dir,ip+".bmp"); FileOutputStream fos=new fileOutputStream(file); byte[] buf=new byte[1024]; int len=0; while(l(len=in.read(buf))!=-1){ fos.write(buf,0,len); } OutputStream out=s.getOutputStream(); out.write("上传成功!",getBytes()); fos.close(); s.close(); } catch(Exception e) { } } }
例:自定义www服务器
public static void main(String[] args) throws IOException { ServerSocket ss=new ServerSocket(9090); socket s=ss.accept();
System.out.println(s.getInetAddress().getHostAddress()+"...Connected"); InputStream in=s.getInputStream(); byte[] buf=new byte[1024]; int len=in.read(buf); String text=new String(buf,0,len); System.out.println(text); PrintWriter out=new PrintWriter(s.getOutputStream(),true); out.println("<font color='red' size='7'>欢迎光临</font>"); s.close(); ss.close(); }
例:模拟浏览器
public class MyBrowser{ public static void main(String[] args) throws UnknownHostException,IOException { Socket s=new Socket("192.168.1.100",8080); //模拟浏览器,给tomcat发送符合http协议的请求消息 PrintWriter out=new printWriter(s.getOutputStream(),true); out.println("GET /myweb/1.html HTTP/1.1"); out.println("Accept: */*"); out.println("Host:192.168.1.100:8080"); out.println("Connection:close"); out.printlnl(); InputStream in=s.getInputStream(); byte[] buf=n ew byte[1024]; int len=in.read(buf); String str=new String(buf,0,len); System.out.println(str); s.close(); } }
例:URL例
public static void main(String[] args) throws NalformedURLException { String str_url="http://192.168.1.100:8080/myhweb/1.html?name=lisi" URL url=new URL(str_url); System.out.println(url.getProtocal()); System.out.println(urlgetHost()); System.out.println(url.getPort()); System.out.println(url.getFile()); System.out.println(url.getPath()); System.out.println(url.getQuery()); //URL的openStream()方法可以打开此地址的Socket流,并返回此连接的输入流,可用以下方法方法模拟浏览器 InputStream in=url.openStream(); byte[] buf=new byte[1024]; int len=in.read(buf); String text=new String(buf,0,len); System.out.println(text); in.close(); }
使用URL对象的openConnection()方法可便的获得输入输出流。
URLConnection conn=url.openConnection(); InputStream in=conn.getInputStream(); //此方法非常简捷 byte[] buf=new byte[1024]; int len=in.read(buf); String text=new String(buf,0,len); Sytem.out.print(text);