网络模型
OSI参考模型
TCP/IP参考模型
-----------------------------------------------
OSI参考模型: | TCP/IP参考模型:
-----------------------------------------------
应用层 | 应用层
表示层 |
会话层 |
-----------------------------------------------
传输层 | 传输层
-----------------------------------------------
网络层 | 网际层
-----------------------------------------------
数据链路层 |
物理层 | 主机至网络层
-----------------------------------------------
网络编程有两种实现方式:即通过TCP协议和UDP协议。
问:TCP和UDP有什么区别:
答:1) TCP协议:属于可靠的连接,在发送数据报之前建立连接,采用三次握手原则,可以保证数据能够完整的传输到目的地,因而传输速度也会比较慢。
2) UDP协议:属于不可靠的连接,发送数据包之前不会建立连接,不会保证数据报到没到达目的地。
(1)UDP:
将数据及源和目的封装成数据包,不需要建立连接
每个数据包的大小限制在64K内
因无连接,是不可靠协议
不需要建立连接,速度快
(2)TCP:
建立连接,形成传输数据的通道
在连接中进行大数据量传输
通过三次握手完成连接,是可靠协议
必须建立连接,效率会稍低
三、网络通信要素:
IP地址:java中对应的是InetAddress类,存在于java.net包中。
InetAddress类:
1、无构造函数,可通过getLocalHost()方法获取InetAddress对象,此方法是静态的,返回此对象。
InetAddress i = InetAddress.getLocalHost();
2、方法:
1)static InetAddress getByName(String host):在给定主机名的情况下获取主机的IP地址
2)static InetAddress[] getAllByName(String host):在给定主机名的情况下,根据系统上配置的名称服务返回IP地址所组成的数组。返回对象不唯一时,用此方法。
3)String getHostAddress():返回IP地址字符串文本形式,以这个为主,即以IP地址为主。
4)String getHostName():返回IP地址主机名。
3、如何获取任意一台主机的IP地址对象:
1)功能:返回InetAddress对象
2)对于任意主机,需要指定传入主机名的参数
public static void main(String[] args) throws UnknownHostException {
/*
* 将IP地址封装成对象。
* InetAddress
* 通过该类的静态方法获取本地主机ip地址对象。
*/
//获取本地主机。
InetAddress ip = InetAddress.getLocalHost();
//获取指定主机ip地址对象。
ip = InetAddress.getByName("http://www.baidu.com");
String str_ip = ip.getHostAddress();
String str_name = ip.getHostName();
System.out.println("ip:"+str_ip);
System.out.println("name:"+str_name);
}
UDP传输
DatagramSocket与DatagramPacket
建立发送端,接收端。
建立数据包。
调用Socket的发送接收方法。
关闭Socket。
发送端与接收端是两个独立的运行程序。
在发送端,要在数据包对象中明确目的地IP及端口
在接收端,要指定监听的端口。
需求:接收到发过来的数据,并将数据中的ip 地址和 端口以及数据内容都打印在显示器
客户端代码:
public static void main(String[] args) throws IOException {
System.out.println("UDP的发送端开启");
//1,既然要进行UDP协议的网络通信,当然要建立UDP的socket服务.
DatagramSocket ds = new DatagramSocket(10000);
//2,确定发送的具体的数据。
String str = "UDP协议传输!";
byte[] buf = str.getBytes();
//3,创建数据包对象,因为DUP协议是需要将数据封装到指定的数据包中。
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),10000);
//4,使用UDPsocket服务的send方法。将数据包发出。
ds.send(dp);
//5,关闭资源。
ds.close();
}
服务器端代码:
public static void main(String[] args) throws IOException {
System.out.println("接收端开启.......");
// 1,创建UDPsocket服务对象。绑定一个指定的端口。给该应用程序分配一个数据标示。也可以称之为监听一个端口。
DatagramSocket ds = new DatagramSocket(1000);
// 2,创建数据包,用于存储接收到的数据,并用数据包对象的方法对数据包中的内容进行解析。
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
// 3,使用socket对象的receive方法将接收到的数据都存储到数据包的对象中。
ds.receive(dp);// 阻塞式方法。
// 4,既然数据已经存储到数据包,直接用数据包的方法对这些数据进行解析。
// 获取IP。
String ip = dp.getAddress().getHostAddress();
// 获取port
int port = dp.getPort();
// 获取数据内容。
byte[] data = dp.getData();
String text = new String(data, 0, dp.getLength());
System.out.println(ip + ":" + port + "--->" + text);
// 5,关闭资源。
ds.close();
}
UDP群聊程序,
收发同时运行,需要一个线程负责收数据,一个线程负责发数据。 定义两个线程任务。
public class UDPChatTest {
public static void main(String[] args) throws SocketException {
//1,创建接收端和发送端。
DatagramSocket send = new DatagramSocket(1919);
DatagramSocket rece = new DatagramSocket(10001);
new Thread(new Send(send)).start();
new Thread(new Rece(rece)).start();
}
}
//定义接收任务
class Send implements Runnable{
private DatagramSocket ds ;
public Send(DatagramSocket ds) {
super();
this.ds = ds;
}
public void run(){
try{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=bufr.readLine())!=null){
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),10001);
ds.send(dp);
if("over".equals(line))
break;
}
ds.close();
}
catch(IOException e){
}
}
}
//定义接收任务。
class Rece implements Runnable{
private DatagramSocket ds ;
public Rece(DatagramSocket ds) {
super();
this.ds = ds;
}
public void run(){
try {
byte[] buf = new byte[1024];
while(true){
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String text = new String(dp.getData(),0,dp.getLength());
System.out.println(ip+":"+text);
if("over".equals(text)){
System.out.println(ip+".....离开聊天室");
}
}
} catch (Exception e) {
}
}
}
TCP传输:
Socket和ServerSocket
建立客户端和服务器端
建立连接后,通过Socket中的IO流进行数据的传输
关闭socket
同样,客户端与服务器端是两个独立的应用程序。
客户端:在该对象建立时就可去连接指定主机,因为TCP是面向俩接的,所以在建立Socket服务时,就要有服务端存在,并连接成功,形成通路后,再通过该通道进行数据的传输。
步骤:
1)创建Socket服务,并指定要连接的主机端口。通路一建立,就会产生Socket流(包括输入流和输出流),通过方法获取
2)为了发送数据,应获取Socket中的输出流,如果要接收服务端的反馈信息,需要获取Socket的输入流
3)通过write()方法将信息写入到流中。
4)关闭Socket流资源
服务端:定义端连接数据,并存放指定地方,需监听一个端口。
步骤:
1)建立服务端的Socket服务,通过ServerSocet带端口参数的构造函数
2)获取连接过来的客户对象,通过ServerSocket的accept()方法,此方法是阻塞式的,如果服务端没有连接到就会等待。
3)客户端若发来数据,则服务端要使用对应的客户端对象,并获取到该客户端对象的读取流发来的数据,并输出到指定目的地。
4)关闭服务端。一般服务端是常开的,因为在实际应用中,随时有客户端在请求连接和服务,所有这里需要定时关闭客户端对象流,避免某一个客户端长时间占用服务器端。
客户端代码:
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("客户端启动.......");
/*
* 定义一个TCP的客户端。
* 发送一段数据给服务器端。
*
*/
Socket s = new Socket("127.0.0.1",10003);
OutputStream out = s.getOutputStream();
out.write("TCP 协议".getBytes());
s.close();
}
服务器端代码:
public static void main(String[] args) throws IOException {
System.out.println("服务端启动.......");
//1,创建TCP服务端对象。并监听一个端口。
ServerSocket ss=new ServerSocket(10003);
//2,获取客户端对象和指定的客户端进行通信。该方法是 accept();
Socket s = ss.accept();
//获取一次客户端IP地址。
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected");
//3,有了socket,就可以获取其中的流,必须要读取客户端的数据,需要获取读取流。
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);
s.close();// 关闭客户端。
ss.close();//关闭服务端。
}
需求:
客户端通过键盘录入数据,发送到服务端。
服务端收到数据,转成大写发回客户端。
当客户端录入over。键盘录入结束
public static void main(String[] args) throws UnknownHostException, IOException {
//1,socket服务是必须的。
Socket s = new Socket("127.0.0.1",10004);
//2,获取键盘录入。源。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//3,目的是网络。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
//4,要获取服务器发回 的大写数据。
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line)){
break;
}
out.println(line);
String str = bufIn.readLine();
System.out.println("str="+str);
}
bufr.close();
s.close();
}
服务器端:
public static void main(String[] args) throws IOException {
// 1,创建ServerSocket服务端socket对象
ServerSocket ss = new ServerSocket(10004);
// 2,获取客户端对象。
Socket s = ss.accept();//阻塞式。
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+".....connected");
//3,使用客户端的读取流对象,读取客户端发来的数据。
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
//4,目的:使用客户端输出流对象,将转成大写的数据发回客户端。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line = null;
while((line=bufIn.readLine())!=null){
System.out.println("client:"+line);
out.println(line.toUpperCase());
}
s.close();
ss.close();
}
public static void main(String[] args) throws UnknownHostException,
IOException {
// 1.创建客户端socket服务
Socket s = new Socket("127.0.0.1", 10006);
FileInputStream fis = new FileInputStream("tempfile\\client1.jpg");
OutputStream out = s.getOutputStream();
byte buf[] = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
out.write(buf,0,len);
}
s.shutdownOutput();
InputStream in =s.getInputStream();
byte bufIn[] = new byte[1024];
int lenIn =in.read(bufIn);
String info =new String(bufIn,0,lenIn);
System.out.println(info);
fis.close();
s.close();
}
服务器端代码:
public static void main(String[] args) throws IOException {
ServerSocket ss= new ServerSocket(10006);
//获取客户端对象
Socket s=ss.accept();
System.out.println(s.getInetAddress().getHostAddress()+"...........");
//读取客户端发来的数据
BufferedReader bufIn =new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter pw =new PrintWriter(new FileWriter("server.jsp"),true);
String line =null;
while((line=bufIn.readLine())!=null)
{
pw.println(line);
}
s.shutdownOutput();
//给服务器端发送一个服务标记,后期可以使用时间毫秒值字符串
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("上传成功");
pw.close();
s.close();
ss.close();
}