java基础十 网络通信和多线程

java网络通信

网络通信基本概念:

通信: 就是从一台机器上的一个软件,发送数据到另一台机器的一个软件上
先发送数据的软件:称为客户端
被动接收数据的软件**:称为服务端**
IP:IP在互联网中能唯一标识一台计算机,是每一台计算机的唯一标识(身份证);网络编程是和远程计算机的通信,所以必须先能定位到远程计算机;
端口:IP帮助解决此问题;一台计算机中可能有很多进程,具体和哪一个进程进行通信,这就得靠端口来识别;

ServerSocket和Socket

Socket

socket可以使一个应用从网络中读取和写入数据,不同计算机上的两个应用可以通过连接发送和接受字节流,当发送消息时,你需要知道对方的ip和端口,在java中,socket指的是java.net.Socket类。

Socket的构造函数
Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 host为远程机器名称或ip地址,port为端口号。
若连接本地的Server,其端口号为8080,可以写成如下格式
new Socket(“localhost”, 8080);
127.0.0.1"也代表本机IP

重要的Socket API:
  用最频繁的三个方法

  • Accept()用于产生"阻塞",直到接受到一个连接,并且返回一个客户端的Socket对象实例。"阻塞"是一个术语,它使程序运行暂时"停留"在这个地方,直到一个会话产生,然后程序继续。
  • getInputStream()获得网络连接输入,同时返回一个IntputStream对象实例,。
  • getOutputStream()连接的另一端将得到输入,同时返回一个OutputStream对象实例。
    注意:可将其两种输出流输入流包装成bufferinputstream和bufferoutputstream
    注意:其中getInputStream和getOutputStream方法均会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用。

ServerSocket

Socket类代表一个客户端套接字,即任何时候连接到一个远程服务器应用时构建所需的socket。现在,要实现一个服务器应用,需要不同的做法。服务器需随时待命,因为不知道客户端什么时候会发来请求,此时,我们需要使用ServerSocket,对应的是java.net.ServerSocket类。
  ServerSocket与Socket不同,ServerSocket是等待客户端的请求,一旦获得一个连接请求,就创建一个Socket示例来与客户端进行通信。
  ServerSocket的构造方法
启动一个socket服务端(本质就是向操作系统注册一个端口号),端口号不可以超过65535
ServerSocket ss = new ServerSocket(1999);

,如果再其后加一个参数,把连接请求队列的长度设为 3。这意味着当队列中有了 3 个连接请求时,如果 Client 再请求连接,就会被 Server拒绝,因为服务器队列已经满了。我们使用的 serverSocket.accept()方法就是从队列中取出连接请求。

`ServerSocket ss = new ServerSocket(1999,3);` 

服务端

服务器接收客户端请求步骤
1服务器建立通信 Serversocket
2服务器建立 Socket接收客户端连接建立
3IO输入流读取客户端发送的数据建立
4IO前出流向客户端发运数据消息
代码

package sockdemo;



import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServiceDemo {
	public static void main(String[] args) throws Exception {
	
			创建一个服务器端 Socket,即 Serversocket,指定绑定的端口,并监听此端口(本质就是向操作系统注册一个端口号)
			ServerSocket ss = new ServerSocket(1999);  
			System.out.println("启动服务器");
			
			
			// 调用 accept()方法开始监听,等待客户端的连接
			Socket sc = ss.accept();
			/**
			 * 从连接中接收数据
			 */获取IO输入流
			InputStream in =  sc.getInputStream();
			
			// 从输入流中拿数据
			
			byte[] b = new byte[1024];
			int num = in.read(b);
			String string = new String(b,0,num);
			System.out.println("收到客户端的消息:" + string);
			
			
			/**
			 * 当接受到连接后,则可以向客户端发送数据
			 */
			 //获取IO输出流
			OutputStream out = sc.getOutputStream();
			//从IO流输出数据
			out.write("我是红红".getBytes());
			//关闭输出流输入流还有连接
			out.close();
			in.close();
			sc.close();
			
}
}

客户端

客户端向服务器发送请求可分为以下步骤:
  1.创建一个Socket实例 ,设置通信的IP和端口
  2.利用I/O流与服务器进行通信
  3.关闭socket

package sockdemo;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;


public class ClientDemo {
	public static void main(String[] args) throws Exception {
        // 创建 Socket通信,设置通信服务器的IP和Port
		Socket sc = new Socket("127.0.0.1", 1999);            
		
		/**
		 * 发送数据
		 */
		//获取输出流
		OutputStream out =  sc.getOutputStream();
		//发出数据
		out.write("who are you?".getBytes());
		
		/**
		 * 接收数据
		 */
		 获取输入流
		InputStream in =  sc.getInputStream();
		接受数据
		byte[] b = new byte[10];
		int num = in.read(b);
		System.out.println(new String(b,0,num));
		
		
		in.close();
		out.close();
		sc.close();
	}

}

改造成常驻服务器

package cn.edu360.javase24.day13.socketdemo3;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo3 {

	public static void main(String[] args) throws Exception {

		ServerSocket ss = new ServerSocket(8080);
		int i = 1;
		while(true) {
			
			Socket sc = ss.accept();
			System.out.println("获得第"+i+"次连接了.....");
			
			InputStream in = sc.getInputStream();
			OutputStream out = sc.getOutputStream();
			
			// 收客户端的第一个问题
			byte[] b = new byte[1024];
			int num = in.read(b);
			System.out.println("收到客户端的第1个问题: " + new String(b,0,num));
			
			// 回答第一个问题
			out.write("我是宇宙无敌大美男".getBytes());
			
			
			// 接收第二个问题
			num = in.read(b);
			System.out.println("收到客户端的第2个问题: " + new String(b,0,num));
			
			
			// 回答第2个问题
			out.write("我的理想女友是按住拉败笔".getBytes());
			
			in.close();
			out.close();
			sc.close();
			i++;
		}
		
	}

}

多线程

一、多线程是什么?为什么要用多线程?

介绍多线程之前要介绍线程,介绍线程则离不开进程。

首先 进程 :是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元;

线程:就是进程中的一个独立控制单元,线程在控制着进程的执行。一个进程中至少有一个进程。

多线程:一个进程中不只有一个线程。

为什么要用多线程:

①、为了更好的利用cpu的资源,如果只有一个线程,则第二个任务必须等到第一个任务结束后才能进行,如果使用多线程则在主线程执行任务的同时可以执行其他任务,而不需要等待;

②、进程之间不能共享数据,线程可以;

③、系统创建进程需要为该进程重新分配系统资源,创建线程代价比较小;

④、Java语言内置了多线程功能支持,简化了java多线程编程。

二、线程的生命周期:

新建 :从新建一个线程对象到程序start() 这个线程之间的状态,都是新建状态;
就绪 :线程对象调用start()方法后,就处于就绪状态,等到JVM里的线程调度器的调度;
运行 :就绪状态下的线程在获取CPU资源后就可以执行run(),此时的线程便处于运行状态,运行状态的线程可变为就绪、阻塞及死亡三种状态。
等待/阻塞/睡眠 :在一个线程执行了sleep(睡眠)、suspend(挂起)等方法后会失去所占有的资源,从而进入阻塞状态,在睡眠结束后可重新进入就绪状态。
终止 :run()方法完成后或发生其他终止条件时就会切换到终止状态。

多线程的实现

  • 写多线程程序的四部曲
  • 1、将需要用多线程方式执行的逻辑,写入一个runnable实现类中(run方法中);
  • 2、创建出这个runnable实现类的对象;
  • 3、利用这个runnable对象构造出n个thread线程;
  • 4、将这n个thread启动(thread.start());

代码演示

实现类写入runnable的演示

package cn.edu360.javase24.day13.thread.demo1;

public class Demo1 implements Runnable {
	private String name;
	
	public Demo1(String name) {            
		this.name = name;
	}
	
	
	public void setName(String name) {          //可以通过这个方法向类中输入参数
		this.name = name;
	}

	@Override                   //将线程要运行的代码放在该run方法中。
	public void run() {                                      
		for (int i = 0; i < 6; i++) {                  
			System.out.println("啊....."+name);
		}
		
	}

}

可以通过




public class Demo1Test {

	public static void main(String[] args) {
		 
		Demo1 demo11 = new Demo1("张三");
		 
		Demo1 demo12 = new Demo1("李四");
		
		Demo1 demo13 = new Demo1("王五");
		
		
		
		Demo2 demo2 = new Demo2();
		//demo1.run();  // 这样调,只是用单线程普通地执行一下这个run方法而已
		
		// 构造一个线程,指定要执行的逻辑,利用这个runnable对象构造出n个thread线程;

		Thread thread1 = new Thread(demo11);
		Thread thread2 = new Thread(demo12);
		Thread thread3 = new Thread(demo13);
		Thread thread4 = new Thread(demo2);
		Thread thread5 = new Thread(demo2);
		
		// 这种调用,只是按顺序进行普通的方法调用,是在一个单线程中挨个执行的
		/*thread1.run();
		thread2.run();
		thread3.run();
		thread4.run();
		thread5.run();*/
		
		// 将这5个线程以多线程的方式同时运行
		thread1.start();
		thread2.start();
		thread3.start();
		thread4.start();
		thread5.start();
		
	}

通过多线程改造常驻服务器

package cn.edu360.javase24.day13.thread.demo2;

import java.net.ServerSocket;
import java.net.Socket;

/**
 * 将对话服务器改造成多线程服务
 * @author ThinkPad
 *
 */
public class ThreadServerDemo {

	public static void main(String[] args) throws Exception {

		ServerSocket ss = new ServerSocket(10000);
		int i=1;
		while (true) {
			
			Socket sc = ss.accept();
			System.out.println("收到连接"+i);
			Talk talk = new Talk(sc);
			new Thread(talk).start();
			i++;

		}

	}

}

talk类连Runnable接口

package cn.edu360.javase24.day13.thread.demo2;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;


/**
 * 用来封装线程中要执行的 对话逻辑(对话流程)
 * @author ThinkPad
 *
 */
public class Talk implements Runnable {
	Socket sc;

	public Talk(Socket sc) {
		this.sc = sc;
	}

	@Override
	public void run() {
		try {
			// 获取输入、输出流
			InputStream in = sc.getInputStream();
			OutputStream out = sc.getOutputStream();
			
			//收第一个问题
			byte[] b = new byte[1024];
			int num = in.read(b);
			System.out.println("收到客户端的问题1:" + new String(b,0,num));
			
			// 回复第一个问题
			out.write("我是宇宙无敌超级美少女战士".getBytes());
			
			// 接收第二个问题
			num = in.read(b);
			System.out.println("收到客户端的问题2:" + new String(b,0,num));
			
			// 回复第二个问题
			out.write("我18岁".getBytes());
			
			
			in.close();
			out.close();
			sc.close();

		} catch (Exception e) {
			System.out.println("发生异常了.......");
		}
发布了44 篇原创文章 · 获赞 0 · 访问量 873

猜你喜欢

转载自blog.csdn.net/heartless_killer/article/details/99685607