网络编程
获取ip地址
InetAddress类成员方法
* static InetAddress getLocalHost()
* 获得本地主机IP地址对象
* static InetAddress getByName(String host)
* 根据IP地址字符串或主机名获得对应的IP地址对象
* String getHostName();获得主机名
* String getHostAddress();获得IP地址字符
public class InetAddressDemo { public static void main(String[] args) throws UnknownHostException { InetAddress byName = InetAddress.getByName("DESKTOP-SDL9NNV"); System.out.println(byName); // DESKTOP-SDL9NNV/192.168.3.26 InetAddress byName1 = InetAddress.getByName("192.168.3.26"); System.out.println(byName1); // /192.168.3.26 String s1 = byName.getHostName(); System.out.println(s1);//DESKTOP-SDL9NNV String s2 = byName.getHostAddress(); System.out.println(s2);//192.168.3.26 } }
UDP协议的特点
* 面向无连接的协议
* 发送端只管发送,不确认对方是否能收到。
* 基于数据包进行数据传输。
* 发送数据的大小限制64K以内
* 因为面向无连接,速度快,但是不可靠。
UDP协议的使用场景
* 即时通讯
* 在线视频
* 网络语音电话
UDP协议相关的两个类
* DatagramPacket
* 数据包对象
* 作用:用来封装要发送或要接收的数据,比如:集装箱
* DategramSocket
* 发送对象
* 作用:用来发送或接收数据包,比如:码头
DatagramPacket类构造方法
* DatagramPacket(byte[] buf, int length, InetAddress address, int port)
* 创建发送端数据包对象
* buf:要发送的内容,字节数组
* length:要发送内容的长度,单位是字节
* address:接收端的IP地址对象
* port:接收端的端口号
* DatagramPacket(byte[] buf, int length)
* 创建接收端的数据包对象
* buf:用来存储接收到内容
* length:能够接收内容的长度
DatagramPacket类常用方法
* int getLength() 获得实际接收到的字节个数
* byte[] getData() 返回数据缓冲区
DatagramSocket类构造方法
* DatagramSocket() 创建发送端的Socket对象,系统会随机分配一个端口号。
* DatagramSocket(int port) 创建接收端的Socket对象并指定端口号
DatagramSocket类成员方法
* void send(DatagramPacket dp) 发送数据包
* void receive(DatagramPacket p) 接收数据包
public class SendDemo { public static void main(String[] args) throws IOException { while (true) { Scanner sc = new Scanner(System.in); String s = sc.next(); // 创建数据包对象 DatagramSocket ds = new DatagramSocket(); //创建发送端的发送对象,因为其构造方法需要字节数组,所以将输入内容转换为字节数组 byte[] bytes = s.getBytes(); DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("DESKTOP-SDL9NNV"), 10086); // 发送数据包 ds.send(dp); //关闭数据包 ds.close(); } } } public class ReceiveDemo { public static void main(String[] args) throws IOException { while (true) { // 创建接收对象DatagramSocket,注意作为接受端需要接受传入的端口号 DatagramSocket ds = new DatagramSocket(10086); // 创建数据包对象,此刻的数据包需要先定义出包的大小,所以先创建数组 byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); // 接收数据包 ds.receive(dp); //输入数据,注意需要输入到指定长度 dp.getLength() String s = new String(dp.getData(), 0, dp.getLength()); System.out.println(dp.getAddress().getHostName() + "收到:" + s); ds.close(); } } }
TCP ==> Transfer Control Protocol ==> 传输控制协议
TCP协议的特点
* 面向连接的协议
* 只能由客户端主动发送数据给服务器端,服务器端接收到数据之后,可以给客户端响应数据。
* 通过三次握手建立连接,连接成功形成数据传输通道。
* 通过四次挥手断开连接
* 基于IO流进行数据传输
* 传输数据大小没有限制
* 因为面向连接的协议,速度慢,但是是可靠的协议。
TCP协议的使用场景
* 文件上传和下载
* 邮件发送和接收
* 远程登录
TCP协议相关的类
* Socket
* 一个该类的对象就代表一个客户端程序。
* ServerSocket
* 一个该类的对象就代表一个服务器端程序。
Socket类构造方法
* Socket(String host, int port)
* 根据ip地址字符串和端口号创建客户端Socket对象
* 注意事项:只要执行该方法,就会立即连接指定的服务器程序,如果连接不成功,则会抛出异常。
如果连接成功,则表示三次握手通过。
Socket类常用方法
* OutputStream getOutputStream(); 获得字节输出流对象
* InputStream getInputStream();获得字节输入流对象
*SocketAddress getRemoteSocketAddress() 返回此套接字连接,或端点的地址 null如果是未连接
public class SendDemo { public static void main(String[] args) throws IOException { System.out.println("客户端启动"); // 创建Socket对象,注意传入ip地址和端口,Socket其实就一个管道 Socket s = new Socket("192.168.3.26",10086); // 获得字节输出流对象 OutputStream os = s.getOutputStream(); //将其封装成打印流直接输入 PrintStream ps = new PrintStream(os); Scanner sc = new Scanner(System.in); while (true) { ps.println(sc.next()); } } } public class ServerDemo { public static void main(String[] args) throws IOException { System.out.println("服务器启动"); // 创建服务器ServerSocket对象,传入端口 ServerSocket ss = new ServerSocket(10086); // ServerSocket接受到管道Socket Socket s = ss.accept(); //读取管道接收的数据 s.getInputStream() BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); //进行循环输出到控制台 String line; while ((line=br.readLine())!=null){ System.out.println(line); } } }
多线程实现客户端与服务端的传输:通过管道Socket来进行多线程
public class ClientDemo2 { public static void main(String[] args) throws IOException { //创建Socket管道,传入ip地址和端口号 Socket s = new Socket("192.168.3.26",10086); //创建缓冲池得到字节输出流 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); //通过训话实现字符的write方法 while (true){ Scanner sc = new Scanner(System.in); bw.write(sc.next()); bw.newLine(); //如果没有空行,读取数据通过readline无法读取 bw.flush(); } } }
public class ServerDemo { public static void main(String[] args) throws IOException { System.out.println("\t\t\t\t\t群聊:团团圆圆一家人"); //创建ServerSocket对象 ServerSocket ss = new ServerSocket(10086); //因为不知道几个客户端,所有用循环来对线程进行实现 while (true){ Socket s = ss.accept(); Thread t = new Thread(new ServerThread(s)); t.start(); } } } class ServerThread implements Runnable{ private Socket s; public ServerThread(Socket s) { this.s=s; } //多线程实现run方法,里面需要写的无疑是数据的读取 @Override public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); Date now = new Date(); String line; while ((line=br.readLine())!=null){ System.out.print(now+":"); System.out.println(s.getRemoteSocketAddress()+"\t发言:\t"+line); } } catch (IOException e) { e.printStackTrace(); } } }