21.七层协议与四层协议
21.1七层协议 OSI
应用层-->表示层-->会话层-->传输层-->网络层-->数据链路层->物理层
四层协议 TCP/IP协议 传输控制协议/网络互连协议
应用层(http, ftp)----------------------->传输层(tcp,udp)->网络层--->网络接口
21.2数据的封装与拆封
发送方-->数据封装
接收方-->数据拆封
21.3网络编程的三要素
(1)IP地址
(2)端口
(3)协议
21.4IP地址InetAddress
package com.bjsxt.net;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class TestInetAddress {
public static void main(String[] args) throws UnknownHostException {
//(1)获取InetAddress对象
InetAddress ia=InetAddress.getByName("110-SHEYANG");//主机就是本机
System.out.println(ia); //说明重写了toString()方法
System.out.println("主机名称:"+ia.getHostName());
System.out.println("主机IP地址:"+ia.getHostAddress());
InetAddress ia2=InetAddress.getByName("www.baidu.com"); //百度的IP地址
System.out.println(ia2);
}
}
21.5URL统一资源定位器/符
package com.bjsxt.net;
import java.net.MalformedURLException;
import java.net.URL;
public class TestURL {
public static void main(String[] args) throws MalformedURLException {
URL u=new URL("https://www.baidu.com");
System.out.println(u); //重写了toString方法()
System.out.println("网址"+u.getHost()); //网址
//System.out.println(u.getPath());获取路径
//System.out.println(u.getPort()); //-1
System.out.println("协议"+u.getProtocol());//http
}
}
21.6编码和解码
package com.bjsxt.net;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
public class EndorAnd {
public static void main(String[] args) throws UnsupportedEncodingException {
//编码
String str=URLEncoder.encode("尚学堂", "utf-8");
System.out.println(str);
//解码
String ss=URLDecoder.decode(str, "utf-8");
System.out.println(ss);
}
}
建立两个项目
(1)客户端项目
发送请求 -->OutputStream
(2)服务器端项目
接收请求 -->InputStream
21.7.1实现客户端与服务器端一次通信, 客户端向服务器发送一句话 helloworld
客户端
package com.bjsxt.client;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Cleint {
public static void main(String[] args) throws UnknownHostException, IOException {
//(1)创建Socket对象,主机,和(服务器端)端口
Socket client=new Socket("192.168.45.241", 9000);
//(2)获取输出流
OutputStream os=client.getOutputStream(); //目的地是192.168.45.241服务器中端口为9000的应用程序
/*//(3)使用处理流处理下
DataOutputStream dos=new DataOutputStream(os);
//(4)发送
dos.writeUTF("你好!");*/
os.write("helloworld!".getBytes());
//关闭
os.close();
client.close();
}
}
服务器端:
package com.bjsxt.server;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
System.out.println("服务器端已开启..................");
//(1)创建ServerSocket对象
ServerSocket server=new ServerSocket(9000);//我在9000等你(客户端)
//(2)监听客户端的请求
Socket s=server.accept(); //监听到一个Socket对象 (客户端)
//(3)接收
InputStream is=s.getInputStream();
byte [] b=new byte[1024];
int length=0;//读到的字节的个数
while((length=is.read(b))!=-1){
System.out.println(s.getInetAddress().getHostAddress()+"--->"+new String(b,0,length));
}
//(4)关闭
s.close();
server.close();
}
}
27.7.2客户端与服务器端实现一次双向通信 模拟用户登录
两个项目
要求:实体类的包名,必须完全相同
(1)实体类 要求:客户端与服务器端的包名,完全相同,
客户端的实体类中的属性与服务器端实体类的属性要求完全相同
(2)客户端
1.创建Socket对象
发送
2.获取输出流
3.发送数据
4.截断输出流
接收
5.获取输入流
6.接收数据
7.截断输入流
8.关闭所有流
客户端:
package com.bjsxt.client;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import com.bjsxt.entity.User;
public class CleintLogin {
public static void main(String[] args) throws UnknownHostException, IOException {
/***用于向服务器发送请求*/
Socket client=new Socket("192.168.45.241", 9000);
//使用输出流
ObjectOutputStream oos=new ObjectOutputStream(client.getOutputStream());
//发送对象
oos.writeObject(getUser()); //调用本类中的获取用户对象方法
client.shutdownOutput();//截断输出流
/**接收来自服务器的响应*/
DataInputStream dis=new DataInputStream(client.getInputStream());
System.out.println(dis.readUTF());
//截断输入流
client.shutdownInput();
//关闭
dis.close();
oos.close();
client.close();
}
//获取用户对象
public static User getUser(){
Scanner input=new Scanner(System.in);
System.out.println("请输入用户名:");
String userName=input.next();
System.out.println("请输入密码:");
String password=input.next();
return new User(userName, password);
}
}
(3)服务器端
1.创建ServerSocket对象
2.监听来自客户端的请求
接收
3.获取输入流
4.接收数据 并验证
5.截断输入流
发送
6.获取输出流
7.发送数据
8.截断输出流
9.关闭所有流
package com.bjsxt.server;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
import com.bjsxt.entity.User;
public class ServerLogin {
public static void main(String[] args) throws IOException, ClassNotFoundException {
System.out.println("服务器已开启............");
/**(1)接收来自客户端的请求*/
ServerSocket server=new ServerSocket(9000);
//服务器监听
Socket client=server.accept();
//接收用户对象
ObjectInputStream ois=new ObjectInputStream(client.getInputStream());
User user=(User)ois.readObject();
System.out.println("IP地址为:"+client.getInetAddress().getHostAddress()+"请求登录");
//截断输入流
client.shutdownInput();
//登录的用户名和密码验证
String result=null;
if("bjsxt".equals(user.getUserName())&&"bjsxt".equals(user.getPassword())){
result="登录成功";
}else{
result="对不起,账号或密码不存在!";
}
/**(2)对客户端的请求作出响应,发送给客户端*/
DataOutputStream dos=new DataOutputStream(client.getOutputStream());
dos.writeUTF(result);
//截断输出流
client.shutdownOutput();
//关闭
dos.close();
ois.close();
client.close();
server.close();
}
}
TCP:
面向连接,可靠的,基于IO流的编程
效率低,安全性高(三次握手)
启动有先后,一定先启服务器,再启客户端,连接成功,谁先发送信息都可以
常见问题
(1)连接被拒绝 (检查IP地址,端口号,关闭防火墙)
(2)端口被占用
(3)连接超时 time out...
IP 地址不通,或IP地址写错,防火墙
UDP:面向无连接 不可靠的,基于数据报/包的编程
接收方和发送方 地位是平等
21.8UDP编程
21.8.1一次单向通信
发送方
package com.bjsxt.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class TestSend {
public static void main(String[] args) throws IOException {
//(1)创建接收和发送的对象
DatagramSocket ds=new DatagramSocket();
//(2)需要对数据进行打包
byte [] buf="helloworld".getBytes();
DatagramPacket dp=new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.45.241"), 9000);
//(3)发送
ds.send(dp);
//(4)关
ds.close();
}
}
接收方
package com.bjsxt.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class TestReceive { //接收方
public static void main(String[] args) throws IOException {
//(1)用于发送和接收, 接收
DatagramSocket ds=new DatagramSocket(9000);//我在9000等你
//(2)创建包裹,准备接收
byte [] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf, buf.length);
ds.receive(dp);//接收
//(3)查看收到的内容
System.out.println(new String(dp.getData(),0,dp.getLength()));
//(4)关闭
ds.close();
}
}
21.8.2实现一次双向通信
先发送,后接收
package com.bjsxt.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class TestSend2 {
public static void main(String[] args) throws IOException {
//(1)创建接收和发送的对象
DatagramSocket ds=new DatagramSocket();
/**发送*/
//(2)需要对数据进行打包
byte [] buf="helloworld".getBytes();
DatagramPacket dp=new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.45.241"), 9000);
//(3)发送
ds.send(dp);
/**发送完毕*/
//(4)关
/**接收*/
byte [] buf2=new byte[1024];
DatagramPacket dp2=new DatagramPacket(buf2, buf2.length);
ds.receive(dp2);
System.out.println(new String(dp2.getData(),0,dp2.getLength()));
ds.close();
}
}
先接收,后发送
package com.bjsxt.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class TestReceive2 { //接收方
public static void main(String[] args) throws IOException {
//(1)用于发送和接收, 接收
DatagramSocket ds=new DatagramSocket(9000);//我在9000等你
/**接收数据*/
//(2)创建包裹,准备接收
byte [] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf, buf.length);
ds.receive(dp);//接收
//(3)查看收到的内容
System.out.println(new String(dp.getData(),0,dp.getLength()));
/***接收完毕*/
/**回复对方*/
byte [] buf2="welcomce to beijing".getBytes();
DatagramPacket dp2=new DatagramPacket(buf2, buf2.length, dp.getAddress(), dp.getPort());
ds.send(dp2);
//(4)关闭
ds.close();
}
}
21.8.3使用UDP实现两人多次聊天 --循环
package com.bjsxt.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class TestSend3 {
public static void main(String[] args) throws IOException {
Scanner input=new Scanner(System.in);
//(1)创建接收和发送的对象
DatagramSocket ds=new DatagramSocket();
while(true){
/**发送*/
//(2)需要对数据进行打包
String s=input.next();//从键盘接收一句话
byte [] buf=s.getBytes();
DatagramPacket dp=new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.45.241"), 9000);
//(3)发送
ds.send(dp);
/**发送完毕*/
//(4)关
/**接收*/
byte [] buf2=new byte[1024];
DatagramPacket dp2=new DatagramPacket(buf2, buf2.length);
ds.receive(dp2);
System.out.println(new String(dp2.getData(),0,dp2.getLength()));
if ("bye".equals(s)) {
break;
}
}
ds.close();
}
}
package com.bjsxt.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Scanner;
public class TestReceive3 { //接收方
public static void main(String[] args) throws IOException {
Scanner input=new Scanner(System.in);
//(1)用于发送和接收, 接收
DatagramSocket ds=new DatagramSocket(9000);//我在9000等你
while(true){
/**接收数据*/
//(2)创建包裹,准备接收
byte [] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf, buf.length);
ds.receive(dp);//接收
//(3)查看收到的内容
System.out.println(new String(dp.getData(),0,dp.getLength()));
/***接收完毕*/
/**回复对方*/
String s=input.next();
byte [] buf2=s.getBytes();
DatagramPacket dp2=new DatagramPacket(buf2, buf2.length, dp.getAddress(), dp.getPort());
ds.send(dp2);
if ("bye".equals(s)) {
break;
}
}
//(4)关闭
ds.close();
}
}