Java网络编程

网络基础知识

IP地址:每个网卡/机器都有一个或多个IP地址
····IPV4:192.168.0.100 每段从0到255
····IPV6:分成8段,每段4个16进制数
eg:FE80:0000:0000:0000:AAAA:0000:00C2:0002
port:端口,0-65535
·····0-1023 OS已经占用,80是web,23是telnet
·····1024-65535 一般程序可用(谨防冲突)
两台机器通讯就是在IP+Port上进行的
TCP通讯协议
·····传输控制协议,面向连接的协议
·····两台机器的可靠无差错的数据传输
·····双向字节流传递
UPD通讯协议
·····用户数据报协议,面向无连接协议
·····不保证可靠的数据传输
·····速度快,也可以在较差网络下使用

Java UDP编程

计算机通讯:数据从一个IP的port出发(发送方),运输到另一个IP的port(接收方
UDP:无连接无状态的通讯协议
······发送方发送消息,如果接收方刚好在目的地,则可以接受。
如果不在,信息就丢失了
······发送方也无法得知是否发送成功
·····UDP的好处:简单 节省 经济
在这里插入图片描述
注意接收方要先于发送方执行,否则信息会丢失

public class UpdRecv {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		DatagramSocket ds = new DatagramSocket(3000); // 数据管道  3000端口
		byte [] buf = new byte[1024];
		DatagramPacket dp = new DatagramPacket(buf, 1024);  //定义集装箱
		
		System.out.println("UdpRecv:我在等待消息");
		ds.receive(dp); // 如果有数据封装入dp中,没有改行一直阻塞
		System.out.println("UdpRecv:我接收到消息");
		String strRecv = new String(dp.getData(),0,dp.getLength()) + "from" +
				dp.getAddress().getHostAddress()+ ":" + dp.getPort();
		System.out.println(strRecv);
		
		// 再定义一个集装箱
		DatagramPacket dp2 = new DatagramPacket(strRecv.getBytes(), strRecv.length(),
				InetAddress.getByName("127.0.0.1"), dp.getPort()); 
		// dp.getPort()获得之前发送方的端口
	}

在这里插入图片描述

public class UpdSend {
	public static void main(String[] args) throws Exception {
		DatagramSocket ds = new DatagramSocket(); // 数据管道     没写则随机选择端口发送
		String str = "hello world"; 
		DatagramPacket dp = new DatagramPacket(str.getBytes(), str.length(),
				InetAddress.getByName("127.0.0.1"), 3000);  //定义集装箱 内容和长度  127.0.0.1默认为本机
		
		System.out.println("UdpSend:我在发消息");
		ds.send(dp); // 如果有数据封装入dp中,没有改行一直阻塞
		System.out.println("UdpSend:我发送消息结束");
		
	}
}

在这里插入图片描述

Java TCP编程

TCP协议:有链接,保证可靠的无误差通讯
(1)服务器:创建一个ServerSocket,等待连接
(2)客户机:创建一个Socket,连接到服务器
(3)服务器:ServerSocket接收到连接,创建一个Socket和客户的Socket建立专线连接,后续服务器和客户机的对话(这一对Socket)会在一个单独的线程(服务器端)上进行
(4)服务器的ServerSocket继续等待连接,返回(1)
在这里插入图片描述
软件服务器:
(1)必须实现一定的功能
(2)必须在一个公开的地址(IP+Port)上对外提供服务

ServerSocket : 服务器码头
·····需要绑定port(以确定公开IP,不指定IP则默认为本机)
·····如果机器有多个网卡(多个IP),需要绑定一个IP地址
Socket : 运输通道
·····客户端需要绑定服务器的地址和Port
·····客户端往Socket输入流写入数据,送到服务端
·····客户端从Socket输出流取服务器端过来的数据
·····服务器反之亦然
在这里插入图片描述
·····服务端等待响应时,处于阻塞状态
·····服务端可以同时响应多个客户端(通过多线程实现)
·····服务端每接受一个客户端,就启动一个独立的线程与之对应
·····客户端和服务端都可以选择关闭这对Socket的通道

实例:
·····服务端先启动,且一直保留
·····客户端后启动,可以先退出

服务端

public class TcpServer {
	public static void main(String[] args) throws IOException {
		ServerSocket ss = new ServerSocket(8001); // 驻守在8001端口
		Socket s = ss.accept();    // 阻塞,等待有客户端连接上来
		System.out.println("Welcome to Java world");
		
		InputStream ips = s.getInputStream(); // 有人连接上来,打开输入流
		OutputStream ops = s.getOutputStream(); // 打开输出流
//		同一个通道,服务器端的输入流就是客户端的输出流
		
//		getBytes使用指定的字符集将字符串编码为 byte序列,并将结果存储到一个新的 byte数组  
		ops.write("Hello, Client!".getBytes()); // 输出一句话给客户端
		
//		把输入流东西进行一次包装,提高读取效率
		BufferedReader br = new BufferedReader(new InputStreamReader(ips));
//		从客户端读一句话
		System.out.println("Client said: " + br.readLine());
		ips.close();
		ops.close();
		s.close();
		ss.close();
	}
}




客户端

public class TcpClient {

	public static void main(String[] args) throws IOException{
		// 需要服务端先开启                目标服务器的地址和端口
		Socket s = new Socket(InetAddress.getByName("127.0.0.1"), 8001); 
		
		InputStream ips = s.getInputStream();  // 开启通道的输入流
		BufferedReader brNet = new BufferedReader(new InputStreamReader(ips));
		// BufferedReader包装字符流  加快读写速度 
		OutputStream ops = s.getOutputStream();// 开启通道的输出流
		DataOutputStream dos = new DataOutputStream(ops);
		
		BufferedReader brkey = new BufferedReader(new InputStreamReader(System.in));
		// 客户端输入是键盘输入,故用System.in
		while(true) {
			String strWord = brkey.readLine();
			if(strWord.equalsIgnoreCase("quit")) {
				break;
			} else {
				System.out.println("I want to send: " + strWord);
//				发送给服务端
				dos.writeBytes(strWord + System.getProperty("line.separator"));
//				接受打印服务端回话
				System.out.println("Server said: " + brNet.readLine());
			}
		}
		dos.close();
		brNet.close();
	}

}

在这里插入图片描述在这里插入图片描述

每来一个客户端,新开一个线程处理(客户端代码和上面的例子一样)

public class TcpServer2 {

	public static void main(String[] args) throws IOException{
		// TODO Auto-generated method stub
		ServerSocket ss = new ServerSocket(8001);
		
		while(true) {
			Socket s = ss.accept();   // 每次收到一个请求,就新建一个Socket
			System.out.println("来了一个client");
			//注意这样写线程多了(1000左右)开销会很大,考虑用并发线程池
			new Thread(new Worker(s)).start(); // Socket作为构造参数提交给新的线程对象     
		}
		
	}

}







public class Worker implements Runnable{
	Socket s;

	public Worker(Socket s) {
		this.s = s;
	}

	//	throws子句的Exception和接口中声明的不一致   故run() throws IOException改为try catch
	public void run(){
		System.out.println("服务人员已经启动");
//		定义通道的(字节)输入流和输出流
		
/*	
* BufferedReader从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
*   为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader(字节流转化为字符流)。例如: 
* BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
*/
		
		try {
			InputStream ips = s.getInputStream();
			OutputStream ops = s.getOutputStream();
			
			BufferedReader br = new BufferedReader(new InputStreamReader(ips));
			DataOutputStream dos = new DataOutputStream(ops);  // 创建一个新的数据输出流,将数据写入指定基础输出流
			while(true) {
				String strWord = br.readLine();
				System.out.println("client said: " + strWord + ":" + strWord.length());
				if(strWord.equalsIgnoreCase("quit")) {
					break;
				}
				String strEcho = strWord + " 666";
				System.out.println("server said:" + strWord + "------->" + strEcho);
				dos.writeBytes(strWord + "------->" + strEcho + System.getProperty("line.separtor"));
			}
			br.close();
			// 关闭包装类,会自动关闭包装类中所包装的底层类,所以不调用ips.close()
			dos.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
		
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值