网络编程 TCP UDP
网络通信
小结:1、网络编程中的两个主要问题:如何准确定位到网络上的一台或多台主机(ping www.baidu.com ( www.baidu.com域名的意义就在于好记,IP地址不好记) 会返回一个IP,这个就是一个主机的地址);找到主机后如何进行通信(通过通信协议 TCP UDP)。
2、网络编程中的要素:IP和端口号,通过这两个能够确定是网络中的哪台主机的哪个应用。网络通信协议(TCP,UDP)。
3、万物皆对象,学习IP的类,端口的类,TCP UDP的类。
IP地址
package internet;
import java.net.InetAddress; //表示IP地址
import java.net.UnknownHostException;
public class TestInetAddress {
public static void main(String[] args) {
try {
InetAddress byName = InetAddress.getByName("127.0.0.1"); //InetAddress里面没有属性和构造器,只能调用静态方法
System.out.println(byName); //查询本机地址
InetAddress byName1 = InetAddress.getByName("localhost");
System.out.println(byName1);
InetAddress localHost = InetAddress.getLocalHost(); //三种方法查询本机地址
System.out.println(localHost);
InetAddress byName2 = InetAddress.getByName("www.baidu.com"); //查询网站IP地址
System.out.println(byName2);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
端口
端口表示计算机上一个程序的进程。
通过IP确定主机后,可以通过不同的端口号区分不同的进程(用来区分不同的软件)。
端口数是0~65535
又分为TCP和UDP两种协议,端口数65535*2,TCP和UDP同时存在80端口不冲突,但一个协议内,端口号不能冲突。
端口分类:公有端口:0~1023,一般是内部用的我们不碰。
Http:80 https:443 ftp:21 Telent:23监听
程序注册端口:1024~49151 ,分配用户或者程序
Tomcat:8080 MySQL:3306 Oracle:1521
动态,私有:49152~65535 一般也不碰
通信协议
传输层:TCP UDP对比:TCP类似于打电话(两者建立连接后,才开始发包),需要连接,稳定,要求三次握手(a第一次请求,对方有应答,a再次请求),四次挥手(a说要结束线程,b说好的,b说结束线程了吗,a说结束了),存在客户端,服务端,传输完成后,释放连接(安全 ),但是效率低。
UDP类似于发短信,不连接,不稳定,(都发过去了,不管对方准没准备好,收没收到),服务端和客户端没有明确的边界。
TCP实现聊天
服务端
package internet.lesson02;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//服务端
public class TcpServerDemo01 {
public static void main(String[] args) {
ServerSocket serverSocket = null; //提升一下对象(变量)的作用域
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
//1、先给自身服务端设置一个地址,等待客户端连接
serverSocket = new ServerSocket(9999);
//4、等待客户端连接过来 //如果想不断等待客户端连接,写一个while(true)把服务端主程序放进去
socket = serverSocket.accept(); //这里面的socket和TcpClientDemo01类里面的Socket socket = new Socket();这个socket是同一个对象,服务端开启一个插槽,客户端创建一个连接对象socket,准备插入插槽,serverSocket这个插槽接收这个连接对象。
//6、读取客户端的消息(获取输入流)
is = socket.getInputStream();
// //7、读取消息
// byte[] buffer = new byte[1024]; //创建一个缓冲区去接数据
// int len;
// //read() 从输入流中读取数据的下一个字节
// //read(byte[] b) 将输入流is中读取一定数量 并将其存储在缓冲区数组 b 中。
// //read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组。
// //read()==-1的含义 这是read()方法中的注释,意识就是read()从输入流中读取下一个字节。如果没有字节可读(也就是read()读到文件最后了)read()返回-1.
// while ((len = is.read(buffer))!=-1){ //is.read(buffer)用is从缓冲区里面读数据,读完的值赋给len,不等于-1,说明里面还有值。
// //public String(byte[] bytes, int offset, int length)这个方法
// //通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。
// //参数: bytes:要解码为字符的 byte 数组
// // offset:要解码的第一个 byte 数组 的索引
// // length:要解码的 byte 数 的长度
// String msg = new String(buffer,0,len); //创建一个字符串开始拼接,把数组buffer中的值写出去,从buffer里面开始拼接,从0位拼到len位。
// System.out.println(msg);
// }
//管道流
baos = new ByteArrayOutputStream(); // 创建一个字节数组输出流ByteArrayOutputStream,把is的输入流接一下,再通过一个管道,输出出来
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer))!=-1){ //假设这个流里有东西
baos.write(buffer,0,len); //把里面的东西写出来,buffer里面去写0位到len位,写出来的还是字节数组,
}
System.out.println(baos.toString()); //把写出来的字节数组toString()一下,转化成字符串输出出来
//toString()返回该对象的字符串表示
// baos.close();
// is.close();
// socket.close();
// serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源:先开后关 管道里面可能还有水,需要一节一节关
if(baos!=null){ //关闭每一个资源的标准写法,一定能处理异常
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {