Java网络编程之详细阐述(值得推荐!!!)

Java网络编程之详细阐述

一、网络编程的概述【理解】

网络编程的概念:
-------网络互连的不同计算机上运行的程序间可以进行数据交换,网络通信其实就是Socket 间的通信;数据在两个Socket间可以通过IO传输。

补充:
1.网络中不同的计算机中程序可以通过网络进行数据交换,可以使用网络编程
2.就算同一台计算机中不同的程序也可以通过网络进行数据交换,也可以使用网络编程
在这里插入图片描述

二、网络通信中的三要素【理解】

网络通信中的三要素:
1、IP地址
网络中设备的唯一标识,如IPv4的32位地址:192.168.1.100。
IPv4,它是由4个字节大小的32位二进制数来表示,如: 00001010000000000000000000000001。
由于二进制形式表示的IP地址非常不便记忆和 处理,因此通常会将IP地址写成十进制的形式,每个字节用一个十进制数字(0-255)表 示,数字间用符号“.”分开,如 “192.168.1.100”。

2、端口号
用于标识进程/程序的逻辑地址,不同进程/程序的标识,一个端口号一个程序,端口号和程序一一对应。
它的取值范围是0-65535,其中,0~1023之间的端口号用于一些知名的网络服务和应 用,用户的普通应用程序需要使用1024以上的端口号,从而避免端口号被另外一个应 用或服务所占用。

3、传输协议
双方通讯的规则,常见协议:UDP,TCP
—UDP:无连接,不可靠,速度快
应用场景:电视,直播,视频会议
—TCP:有连接,可靠,速度慢
应用场景:上传,下载,发邮件
在这里插入图片描述重要:
TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
第一次握手:客户端向服务器端发出连接请求,等待服务器确认。
第二次握手:服务器端向客户端回送一个响应,通知客户端收到了连接请求。
第三次握手:客户端再次向服务器端发送确认信息,确认连接。

在这里插入图片描述UDP协议中,当一台计算机向另一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据后,也不会向发送端反馈是否收到数据。
在这里插入图片描述

三、InetAddress的概述和测试【应用】

阐述InetAddress的概念以及如何获取本机IP和主机名的案例

InetAddress的概念:
为了方便我们对IP地址的获取和操作,java提供了一个类InetAddress供我们使用。
即IP = InetAddress

常用API:

  • 获取网络中主机名和IP
    InetAddress inetAddress = InetAddress.getByName(“主机名”);
    InetAddress inetAddress = InetAddress.getByName(“主机IP地址”);

代码:

/*
 * InetAddress:此类表示互联网协议 (IP) 地址。 
 */
public class InetAddressDemo {
	public static void main(String[] args) throws UnknownHostException   {
		//static InetAddress getByName(String host) 
		//InetAddress address = InetAddress.getByName("itheima");//主机名
		InetAddress address = InetAddress.getByName("192.168.1.107");//ip地址是唯一的
	
		//System.out.println(address);//itheima/192.168.1.107 ipconfig
		
		String hostAddress = address.getHostAddress();//192.168.1.107 返回IP地址
		String hostName = address.getHostName();//itheima	返回主机名
		
		System.out.println(hostAddress);
		System.out.println(hostName);
	}
}

在这里插入图片描述

四、UDP协议发送数据【应用】

在这里插入图片描述
在这里插入图片描述
常用API:
1.创建发送端Socket

  • DatagramSocket()

2.创建发送端数据包

  • DatagramPacket(byte[] buf, int length, InetAddress address, int port)

3.发送端发送数据包

  • void send(DatagramPacket p)

4.发送端释放资源

  • void close()

代码:

/*
 * 使用UDP协议发送数据
		创建发送端Socket对象
		创建数据并打包
		发送数据
		释放资源
 * 
 * DatagramSocket:此类表示用来发送和接收数据,基于UDP协议的
 * 
 * DatagramSocket() :创建Socket对象并随机分配端口号
* DatagramSocket(int port) :创建Socket对象并指定端口号
 */
public class SendDemo {
	public static void main(String[] args) throws IOException  {
		//创建发送端Socket对象
		DatagramSocket ds = new DatagramSocket();
		//创建数据并打包
		/*
		 * DatagramPacket :此类表示数据报包
		 * 数据 byte[]
		 * 设备的地址 ip
		 * 进程的地址  端口号
		   DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
		 */
		
		String s = "hello udp,im comming!";
		byte[] bys = s.getBytes();
		int length = bys.length;
		InetAddress address = InetAddress.getByName("itheima");//发送给当前设备
		int port = 8888;
		//打包
		DatagramPacket dp = new DatagramPacket(bys,length,address,port);
		//发送数据
		ds.send(dp);
		//释放资源
		ds.close();
	}
}

五、UDP协议接收数据【应用】

常用API:
1.创建接收端Socket,这个port端口号必须和发送端指定的端口号相同

  • DatagramSocket(int port)

2.创建接收端数据包

  • DatagramPacket(byte[] buf, int length)

3.接收端接收数据

  • void receive(DatagramPacket p)

4.从数据包中解析数据

  • byte[] getData()
    int getLength()

5.接收端释放资源

  • void close()

代码:

/*
 * 使用UDP协议接收数据
		创建接收端Socket对象
		接收数据
		解析数据
		输出数据
		释放资源
 */
public class ReceiveDemo {
	public static void main(String[] args) throws IOException {
		//创建接收端Socket对象
		DatagramSocket ds = new DatagramSocket(8888);
		//接收数据
		//DatagramPacket(byte[] buf, int length) 
		byte[] bys = new byte[1024];
		DatagramPacket dp = new DatagramPacket(bys,bys.length);
				
		System.out.println(1);
		ds.receive(dp);//阻塞
		System.out.println(2);
		
		//解析数据
		//InetAddress getAddress() : 获取发送端的IP对象
		InetAddress address = dp.getAddress();
		//byte[] getData()  :获取接收到的数据,也可以直接使用创建包对象时的数组
		byte[] data = dp.getData();
		//int getLength()  :获取具体收到数据的长度
		int length = dp.getLength();
		
		//输出数据
		System.out.println("sender ---> " + address.getHostAddress());
		//System.out.println(new String(data,0,length));
		System.out.println(new String(bys,0,length));
		//释放资源
		ds.close();

	}
}
UDP协议收发数据注意事项:

注意事项:

  • 如果发送端和接收端的端口号不相同,程序不会出错,但接收端收不到数据。
  • 如果接收端已经启动,这时又再一次启动接收端,程序会出错,Exception in thread “main” java.net.BindException: Address already in use: Cannot bind
    端口号已经绑定了,这个错误同样适用于TCP协议。
  • 先启动接收端,后启动发送端。

六、TCP协议发送数据【应用】

在这里插入图片描述常用API:
1.创建发送端/客户端Socket,自动建立连接,如果连接没有建立,会出错

  • Socket(InetAddress address, int port)
    Socket(String host, int port)

2.获取字节输出流

  • OutputStream getOutputStream()

3.发送数据

  • void write(byte[] b)

4.发送端/客户端释放资源

  • void close()

代码:

/*
 * 使用TCP协议发送数据
		创建发送端Socket对象(创建连接)
		获取输出流对象
		发送数据
		释放资源
		
	Socket(InetAddress address, int port) 

    在TCP协议下,必须先运行接收端,否则出错,信息如下:
	Exception in thread "main" java.net.ConnectException: Connection refused: connect

 */
public class ClientDemo {
	public static void main(String[] args) throws IOException {
		//创建发送端Socket对象(创建连接)
		Socket s = new Socket(InetAddress.getByName("127.0.0.1"),10086);
		//获取输出流对象
		OutputStream os = s.getOutputStream();
		//发送数据
		String str = "hello tcp,张鑫!!!";
		os.write(str.getBytes());
		//释放资源
		//os.close();
		s.close();
	}
}

七、TCP协议接收数据【应用】

常用API:
1.创建接收端/服务端Socket,这里的端口号要与发送端/客户端指定的端口号相同

  • ServerSocket(int port)

2.接收端/服务端监听发送端/客户端

  • Socket accept()

3.获取字节输入流

  • InputStream getInputStream()

4.接收数据

  • int read(byte[] b)

5.接收端/服务端释放资源

  • void close()

代码:

/*
 * 使用TCP协议接收数据
 		创建接收端Socket对象
 		监听(阻塞)
 		获取输入流对象
 		获取数据
 		输出数据
 		释放资源
 		
 	ServerSocket:接收端,服务端Socket
 	ServerSocket(int port) 
 	Socket accept() 
 
 */
public class ServerDemo {
	public static void main(String[] args) throws IOException  {
		//创建接收端Socket对象
		ServerSocket ss = new ServerSocket(10086);
 		//监听(阻塞)
		Socket s = ss.accept();
 		//获取输入流对象
		InputStream is = s.getInputStream();
 		//获取数据
		byte[] bys = new byte[1024];
		int len;//用于存储读到的字节个数
		len = is.read(bys);
 		//输出数据
		InetAddress address = s.getInetAddress();
		System.out.println("client ---> " + address.getHostName());
		System.out.println(new String(bys,0,len));
 		//释放资源
		s.close();
		//ss.close();//企业中的服务端全年不关
	}
}

八、用TCP协议发送数据并将接收到的数据转换成大写返回【应用】

图解流程:
在这里插入图片描述

客户端:

/*
 	需求:使用TCP协议发送数据,并将接收到的数据转换成大写返回
 	
 	客户端发出数据
 	服务端接收数据
 	服务端转换数据
 	服务端发出数据
 	客户端接收数据
 	
 */
public class ClientDemo {
	public static void main(String[] args) throws IOException {
		//创建客户端Socket对象
		Socket s = new Socket(InetAddress.getByName("itheima"),10010);
		//获取输出流对象
		OutputStream os = s.getOutputStream();
		//发出数据
		os.write("tcp,im comming again!!!".getBytes());

		
		//获取输入流对象
		InputStream is = s.getInputStream();
		byte[] bys = new byte[1024];
		int len;//用于存储读取到的字节个数
		//接收数据
		len = is.read(bys);
		//输出数据
		System.out.println(new String(bys,0,len));
		
		//释放资源
		s.close();
		
	}
}

服务端:

public class ServerDemo {
	public static void main(String[] args) throws IOException {
		//创建服务端Socket对象
		ServerSocket ss = new ServerSocket(10010);
		//监听
		Socket s = ss.accept();
		//获取输入流对象
		InputStream is = s.getInputStream();
		//获取数据
		byte[] bys = new byte[1024];
		int len;//用于存储读取到的字节个数
		len = is.read(bys);
		String str = new String(bys,0,len);
		//输出数据
		System.out.println(str);
		//转换数据
		String upperStr = str.toUpperCase();
		//获取输出流对象
		OutputStream os = s.getOutputStream();
		//返回数据(发出数据)
		os.write(upperStr.getBytes());
		
		//释放资源
		s.close();
		//ss.close();//服务端一般不关闭
		
	}
}

九、模拟用户登录案例【应用】

常用的API:

  • 创建字符输出流,直接将字节输出流进行封装,true表示自动刷新
    PrintWriter(OutputStream out, boolean autoFlush)

User类:

public class User {
	private String username;//用户名
	private String password;//密码
	public User() {
		super();
		// TODO Auto-generated constructor stub
	}
	public User(String username, String password) {
		super();
		this.username = username;
		this.password = password;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		User other = (User) obj;
		if (password == null) {
			if (other.password != null)
				return false;
		} else if (!password.equals(other.password))
			return false;
		if (username == null) {
			if (other.username != null)
				return false;
		} else if (!username.equals(other.username))
			return false;
		return true;
	}
}

UserDB:

public class UserDB {
	private static List<User> users = new ArrayList<User>();
	
	static {
		users.add(new User("zhangsan","123456"));
		users.add(new User("lisi","654321"));
		users.add(new User("itheima","itheima"));
		users.add(new User("admin","password"));
	}
	
	public static List<User> getUsers() {
		return users;
	}
}

ServerTest:

public class ServerTest {
	public static void main(String[] args) throws IOException {
		//创建服务器端Socket对象
		ServerSocket ss = new ServerSocket(8888);
		//监听
		Socket s = ss.accept();
		//获取输入流对象
		BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
		//获取用户名和密码
		String username = br.readLine();
		String password = br.readLine();
		//判断用户名和密码是否正确
		boolean flag = false;
	
		/*if("itheima".equals(username) && "123456".equals(password)) {
			flag = true;
		}*/
		
		List<User> users = UserDB.getUsers();
		User user = new User(username,password);
		if(users.contains(user)) {
			//匹配成功
			flag = true;
		}
		
		
		//获取输出流对象
		PrintWriter out = new PrintWriter(s.getOutputStream(),true);
		
		//返回判断信息
		if(flag) {
			out.println("登陆成功");
		}
		else {
			out.println("登陆失败");
		}
		//释放资源
		s.close();
		//ss.close();//服务器一般不关闭
	}
}

如果要让服务器端TcpServer永远监听客户端的连接,需要使用死循环
代码:

public class TcpServer {
    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket(8888);
        while (true) {
            Socket s = ss.accept();

            InputStream is = s.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String username = br.readLine();
            String password = br.readLine();
            boolean flag = false;
            User user = new User(username,password);
            List<User> list = UserDB.getList();
            if(list.contains(user)){
                flag = true;
            }
            OutputStream os = s.getOutputStream();
            PrintWriter pw = new PrintWriter(os,true);
            if(flag){
                pw.println("登录成功");
            }else{
                pw.println("登录失败");
            }

            s.close();
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值