public class thread {
public static void main(String[] args) {
new ThreadA().start();
new Thread(new RA()).start();
}
}
class ThreadA extends Thread {
public void run() {
for(int i=0;i<=100;i++){
System.out.print(i+" ");
}
}
}
class RA implements Runnable {
public void run() {
for(int i=0;i<=100;i++){
System.out.print(i+" ");
}
}
}
2)线程同步
同一进程的多个线程共享同一片存储空间,为了避免访问冲突的情况,JAVA提供了一种同步机制的办法,用synchronized关键字来修饰共享的代码块,确保在某个时刻只有一个线程允许执行特定的代码块。
当一个线程在访问被synchronized修饰的数据时,会将其“上锁”,阻止其他线程访问。只有当前线程访问完这部分数据后释放锁标志,其他线程才可以访问。
注意:无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或方法当作锁。
Executors.newFixedThreadPool(int nThreads)
当nThreads=5时,意味着线程池每次只能同时执行5个线程,相应处理5个任务;
ExecutorService pool = Executors.newFixedThreadPool(5);②线程池提交
线程池提交任务的方式有两种,分别为execute()和 submit()⽅法
execute()⽅法⽤于提交不需要返回值的任务,⽆法判断任务是否被线程池执⾏成功。
submit()⽅法⽤于提交需要返回值的任务。线程池会返回⼀个future类型的对象,可通过future对象判断线程是否执行成功,获取返回值等。
Runnable task = new MyRunnable(); pool.submit(task);③线程池关闭
ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和shutdownNow()
shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
pool.shutdown();2.TCP和UDP区别 3.TCP 1) 创建TCP服务器的基本过程
String serverName="localhost"; int serverPort = 5000; ServerSocket ss = new ServerSocket(); //创建服务器监听套接字; SocketAddress serverAddr = new InetSocketAddress(serverName,serverPort); ss.bind(serverAddr); //绑定到服务器工作地址 Socket s = ss.accept(); //监听...如果监听到客户端的连接请求,接受并返回对应的客户端套接字Socket,否则阻塞(一直监听)2) 创建TCP客户端的基本过程
String serverName="localhost"; int serverPort = 5000; Socket s = new Socket(); SocketAddress serverAddr=new InetSocketAddress(serverName,serverPort); s.connect(serverAddr);3) TCP通信基本编程实现,并掌握如何应用多线程技术实现并行通信 TCP单线程通信 服务端
String serverName="localhost";
int serverPort = 5000;
ServerSocket ss ;
SocketAddress serverAddr=new InetSocketAddress(serverName,serverPort);
ss=new ServerSocket(); //创建服务器监听套接字
ss.bind(serverAddr); //绑定到服务器工作地址
while (true){
Socket s = ss.accept(); //监听...如果监听到客户端的连接请求,接受并返回对应的客户端套接字Socket,否则阻塞(一直监听)
BufferedReader in =
new BufferedReader(new InputStreamReader(s.getInputStream(),"UTF-8"));
BufferedWriter out =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));
BufferedReader sc = new BufferedReader(new InputStreamReader(System.in));
String msg=null;
while ((msg=in.readLine())!=null){//接收客户端发过来的信息(1行)并返回,否则阻塞(等待客户发送信息过来)
System.out.println(msg);
if(msg.equals("bye")){
break;
}
String send_msg = sc.readLine();
out.write(send_msg);//回复信息给客户端,如果客户发过来的是"hi",则回复的是"echo:hi";将此信息写入到输出流
out.newline();//再将一个换行符写入到输出流
out.flush();//刷新流,确认将输出流中的数据发送出去给服务器
}
sc.close();
in.close();
out.close();
s.close();
}
客户端
String serverName="localhost";
int serverPort = 5000;
Socket s = new Socket();
SocketAddress serverAddr=new InetSocketAddress(serverName,serverPort);
s.connect(serverAddr);
BufferedReader in =
new BufferedReader(new InputStreamReader(s.getInputStream(),"UTF-8"));
BufferedWriter out =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String msg = null;
while((msg=br.readLine())!=null){//从键盘读入信息(1行)并返回,否则阻塞(等待用户从键盘敲入一行)
out.write(msg);//将信息写入到输出流
out.newline();//再将一个换行符写入到输出流
out.flush();//刷新流,确认将输出流中的数据发送出去给服务器
if(msg.equals("bye")){
break;
}
System.out.println(in.readLine());
}
br.close();
in.close();
out.close();
s.close();
TCP多线程通信
服务端
try (ServerSocket listenSocket = new ServerSocket()){
SocketAddress serverAddr=new InetSocketAddress("localhost",5000);
listenSocket.bind(serverAddr);
System.out.println("服务器启动成功!开始在localhost的5000端口侦听连接...");
while (true){
try {
//2.监听端口并接收客户端的连接请求
Socket clientSocket = listenSocket.accept();
new ClientThread(clientSocket).start();
}catch (IOException ex) {
System.out.println("异常信息:"+ex.getMessage());
}
}
} catch (IOException ex) {
System.out.println("异常信息:"+ex.getMessage());
}
多线程ClientThread
public class ClientThread extends Thread {
Socket socket;
public ClientThread (Socket socket){
this.socket = socket;
}
public void run(){
try( //带资源的try
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()))
){
System.out.println("客户机连接成功!客户机地址和端口:"+socket.getRemoteSocketAddress());
String recv_msg="";
//从客户机接收字符串
while((recv_msg=in.readLine())!=null){
System.out.println("服务器收到字符串:"+recv_msg);
//向客户机回送字符串
out.write(recv_msg);
out.newline();
out.flush();
System.out.println("服务器回送字符串成功:"+recv_msg);
if(recv_msg.equals("bye")){
break;
}
}
} catch (IOException ex) {
System.out.println("异常信息"+ex.getMessage());
} finally {
//关闭套接字和流
try {
if (socket != null) socket.close();
} catch (IOException ex) {
System.out.println("异常信息"+ex.getMessage());
}
}
}
}
客户端
String serverName="localhost";
int serverPort = 5000;
Socket s = new Socket();
SocketAddress serverAddr=new InetSocketAddress(serverName,serverPort);
s.connect(serverAddr);
BufferedReader in =
new BufferedReader(new InputStreamReader(s.getInputStream(),"UTF-8"));
BufferedWriter out =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String msg = null;
while((msg=br.readLine())!=null){//从键盘读入信息(1行)并返回,否则阻塞(等待用户从键盘敲入一行)
out.write(msg);//将信息写入到输出流
out.newline();//再将一个换行符写入到输出流
out.flush();//刷新流,确认将输出流中的数据发送出去给服务器
if(msg.equals("bye")){
break;
}
System.out.println(in.readLine());
}
br.close();
in.close();
out.close();
s.close();
利用线程池去处理多线程
服务端
ExecutorService pool = null;
//1.启动服务器
try (ServerSocket listenSocket = new ServerSocket()){
SocketAddress serverAddr=new InetSocketAddress("localhost",5000);
listenSocket.bind(serverAddr);
System.out.println("服务器启动成功!开始在localhost的5000端口侦听连接...");
pool = Executors.newFixedThreadPool(10);
while (true){
try {
//2.监听端口并接收客户端的连接请求
Socket clientSocket = listenSocket.accept();
//new ClientThread(clientSocket).start();
pool.submit(new ClientThread(clientSocket));
}catch (IOException ex) {
System.out.println("异常信息:"+ex.getMessage());
}
}
} catch (IOException ex) {
System.out.println("异常信息:"+ex.getMessage());
} finally{
if(pool!=null){
pool.shutdown();
}
}
多线程ClientThread
public class ClientThread extends Thread {
Socket socket;
public ClientThread (Socket socket){
this.socket = socket;
}
public void run(){
try( //带资源的try
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()))
){
System.out.println("客户机连接成功!客户机地址和端口:"+socket.getRemoteSocketAddress());
String recv_msg="";
//从客户机接收字符串
while((recv_msg=in.readLine())!=null){
System.out.println("服务器收到字符串:"+recv_msg);
//向客户机回送字符串
out.write(recv_msg);
out.newline();
out.flush();
System.out.println("服务器回送字符串成功:"+recv_msg);
if(recv_msg.equals("bye")){
break;
}
}
} catch (IOException ex) {
System.out.println("异常信息"+ex.getMessage());
} finally {
//关闭套接字和流
try {
if (socket != null) socket.close();
} catch (IOException ex) {
System.out.println("异常信息"+ex.getMessage());
}
}
}
}
客户端
String serverName="localhost";
int serverPort = 5000;
Socket s = new Socket();
SocketAddress serverAddr=new InetSocketAddress(serverName,serverPort);
s.connect(serverAddr);
BufferedReader in =
new BufferedReader(new InputStreamReader(s.getInputStream(),"UTF-8"));
BufferedWriter out =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String msg = null;
while((msg=br.readLine())!=null){//从键盘读入信息(1行)并返回,否则阻塞(等待用户从键盘敲入一行)
out.write(msg);//将信息写入到输出流
out.newline();//再将一个换行符写入到输出流
out.flush();//刷新流,确认将输出流中的数据发送出去给服务器
if(msg.equals("bye")){
break;
}
System.out.println(in.readLine());
}
br.close();
in.close();
out.close();
s.close();
4)文件传输
客户端-接收端
package file_tcp;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
public class MyFileReceiver {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
ServerSocket ss = new ServerSocket(8000);
Socket s = ss.accept();
//构建套接字输入流,接收客户端数据
DataInputStream in=new DataInputStream(
new BufferedInputStream(
s.getInputStream()));
//构建套接字输出流,以发送数据给客户端
BufferedWriter out=new BufferedWriter(
new OutputStreamWriter(
s.getOutputStream()));
//接收文件名、文件长度
String filename=in.readUTF(); //文件名
int fileLen=(int)in.readLong(); //文件长度
//创建文件输出流
File f =new File(new Date().getTime() + "." + filename);
DataOutputStream dos =new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(f)));
byte buffer[] = new byte[8096];
int numRead = 0;
int numFinished = 0;
while (numFinished=fileLen) {//文件接收完成?
out.write("M_DONE"); //回送成功消息
System.out.println(filename +" 接收成功!");
}else {
out.write("M_LOST"); //回送失败消息
System.out.println(filename +" 接收失败!") ;
}//end if
out.newline();
out.flush();
out.close();
s.close();
ss.close();
}
}
服务器-发送端
package file_tcp;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class MyFileSender {
public static void main(String[] args) throws UnknownHostException, IOException {
// TODO Auto-generated method stub
File f = new File("A.txt");
Socket s =new Socket("localhost",8000);
//构建套接字输出流,以发送数据给服务器
DataOutputStream out=new DataOutputStream(
new BufferedOutputStream(
s.getOutputStream()));
//构建套接字输入流,接收服务器反馈信息
BufferedReader br=new BufferedReader(
new InputStreamReader(
s.getInputStream()));
//构建文件输入流
DataInputStream in=new DataInputStream(
new BufferedInputStream(
new FileInputStream(f)));
long fileLen=f.length(); //计算文件长度
//发送文件名称、文件长度
out.writeUTF(f.getName());
out.writeLong(fileLen);
out.flush();
//传送文件内容
int numRead=0; //单次读取的字节数
int numFinished=0; //总完成字节数
byte[] buffer=new byte[8096];
while (numFinished
5)Socket 与 TCP三次握手关系
客户端connect方法后触发三次握手
握手成功后,在服务器端,对应的连接会加入accept队列.服务器执行accept 方法
只从accept队列取出一个连接进行处理,因此accept 方法与三次握手无关。
4.安全通信
1)SSL的概念,协议的作用,JDK中提供的相关的主要的包及类
概念与作用
SSL:安全套接字层协议 (Secure Sockets Layer,SSL),SSL提供加密,来源认证和数据完整性验证功能,为Web浏览器和TCP C/S提供安全通信。
TLS:传输层安全协议(Transport Layer Security,TLS),SSL升级版
JSSE:Java安全Socket扩展(Java Secure Sockets Extension,JSSE),使用SSL和TLS保护网络通信安全
相关类
安全Socket编程的主要类与接口:
①javax.net.ssl包:
SSLServerSocket(ServerSocket的子类)、
SSLSocket(Socket的子类)、
KeyManagerFactory、TrustManagerFactory、
SSLContext、SSLSocketFactory
②Java.security包:
KeyStore、MessageDigest、Key等等
2)加密算法
对称加密:加密和解密都使用相同的密钥,如DES、AES;
非对称加密: 加密和解密使用不同的密钥,即,密钥对(公钥、私钥),如RSA;
✳用公钥加密的信息,必须用私钥才能解密;
✳用私钥加密的信息,必须用公钥才能解密;
由于非对称算法加密计算量大,不适合大的数据量, 解决方法是:应用对称密钥加解密数据,应用非对称密钥验证和加解密对称密钥的相关信息。
3) 创建安全客户端与服务器Socket的过程
5.UDP
UDP服务端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
public class Server {
public static void main(String[] args) {
//1.启动服务器
SocketAddress sa = new InetSocketAddress("localhost",8000);
try (DatagramSocket s = new DatagramSocket(sa)){
System.out.println("服务器启动成功!开始在localhost的8000端口侦听连接...");
while (true){
try {
DatagramPacket pin = new DatagramPacket(new byte[512],512);
s.receive(pin);
String msg = new String(pin.getData(),0, pin.getLength());
System.out.println(msg);
String replyMsg = "echo: " + msg;
DatagramPacket pout = new DatagramPacket(
replyMsg.getBytes(),replyMsg.getBytes().length,pin.getAddress(),pin.getPort());
s.send(pout);
System.out.println(pin.getAddress()+":"+pin.getPort());
}catch (IOException ex) {
System.out.println("异常信息:"+ex.getMessage());
}
}
} catch (IOException ex) {
System.out.println("异常信息:"+ex.getMessage());
}
}
}
UDP客户端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
public class Client {
public static void main(String[] args) {
DatagramSocket s=null;
String serverName="localhost";
int serverPort = 8000;
BufferedReader br=null;
try{
s = new DatagramSocket(0);//系统自动分配一个端口,也可以指定一个端口
InetSocketAddress ia=new InetSocketAddress(serverName,serverPort);//服务器的地址
br = new BufferedReader(new InputStreamReader(System.in));//键盘输入
String msg = null;
while ((msg = br.readLine())!=null){
DatagramPacket pout = new DatagramPacket(msg.getBytes(),msg.getBytes().length,ia);
s.send(pout);
DatagramPacket pin = new DatagramPacket(new byte[512],512);
s.receive(pin);
//socket收到的数据的长度不一定是pin包定义的数组的大小的,可以通过pin.getLength()取得接收到的数据的长度。
//将接收到的数据转换成字符串时,可以设定从包里取多少数据,如下:
System.out.println(new String(pin.getData(),0, pin.getLength()));
if(msg.equals("bye")){
break;
}
}
}catch (Exception e){
e.printStackTrace();
} finally{
try {
if(s!=null) s.close();
if(br!=null) br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
6.组播
组播地址:组播中的一组主机所共享的地址
组播地址是范围在224.0.0.0~239.255.255.255之间的IP地址
224.0.0.0~224.0.0.255 为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用; 224.0.1.0~224.0.1.255 是公用组播地址,可以用于Internet; 224.0.2.0~238.255.255.255 为用户可用的组播地址(临时组地址),全网范围内有效; 239.0.0.0~239.255.255.255 为本地管理组播地址,仅在特定的本地范围内有效。
组播通信过程
组播接收端
package multicast;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class MultiCastReceiver {
public static void main(String[] args) {
// TODO Auto-generated method stub
try(MulticastSocket socket = new MulticastSocket(4000)){
InetAddress ia = InetAddress.getByName("225.0.1.1");
socket.joinGroup(ia);
while(true){
DatagramPacket packet = new DatagramPacket(new byte[512],512);
socket.receive(packet);
String msg = new String (packet.getData(), 0, packet.getLength());
System.out.println(msg);
if(msg.equals("bye")){
break;
}
}
socket.leaveGroup(ia);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
组播发送端
package multicast;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class MultiCastSender {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
try(MulticastSocket socket = new MulticastSocket(4000);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in))){
InetAddress ia = InetAddress.getByName("225.0.1.1");
socket.joinGroup(ia);
//socket.setTimeToLive(0);//如果值为0,则只能在本机传播,而1则只能在本地子网中传播
socket.setLoopbackMode(true);//参数为disable,当等于false时,组播的信息也发回自己
new SelfReceiver(socket).start();//接收自己所组播的信息
String msg = null;
while ((msg=br.readLine())!=null){
DatagramPacket p = new DatagramPacket(msg.getBytes(), msg.getBytes().length,
ia, 4000);
socket.send(p);
}
socket.leaveGroup(ia);
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
class SelfReceiver extends Thread {
MulticastSocket socket;
public SelfReceiver(MulticastSocket socket){
this.socket = socket;
}
public void run(){
while(true){
try {
DatagramPacket packet = new DatagramPacket(new byte[512],512);
socket.receive(packet);
String msg = new String (packet.getData(), 0, packet.getLength());
System.out.println("接收信息:" + msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
7.非阻塞I/O
1)服务器和客户端的基本事件
2) 判断哪种事件
key.isAcceptable(): 处理接收连接就绪事件
key.isReadable(): 处理读就绪事件
key.isWritable(): 处理写就绪事件
8. 流
1)分成字节流与字符流,通常图片或音频视频文件用字节流,而文本用字符流,但是如果单纯地复制或传输文本文件,则用字节流
2)基类:字节流的基类是InputStream、OutputStream,字符流是Reader、Writer,为抽象类,不能直接创建对象,
通过重载read、write方法来实现不同的读写操作
3)常用的字节流类和字符流类及其方法的应用,如缓冲流,文件流,数据流
-缓冲流:输入时可以提供readline的方法读取一行字符,输入时可以直接write字符串,需要通过flush()刷新流。
-文件流:当文件不存在时,输入流会异常,而输出流则会创建文件,设置Append参数可以覆盖或追加信息
-数据流:不同数据类型的数据的读写,提供不同的方法,如readUTF, readLong…
9.HTTP:
get常用于向服务器索取信息;post常用于向服务器提交信息
获取网页内容方式
1) 使用openStream方法获取网页html内容
创建URL对象(给定url地址),通过调用openStream()的方法来获取资源
try {
URL u = new URL("http://xxx/");
BufferedReader in = null;
in = new BufferedReader(
new InputStreamReader(u.openStream(),"UTF-8"));
String str;
while ((str= in.readLine())!=null){
System.out.println(str);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
将会输出当前网站的HTML信息
2)利用HttpGet
创建HttpGet对象(给定url地址),通过httpClient.execute(httpGet)获取资源及信息,判断状态码以进入不同的操作处理。
package HTTP;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
public class httpclient_getHTML {
public static void main(String[] args) throws IOException {
String link = "http://xxx";
String outfile = "test.html";
HttpClient httpClient = HttpClientBuilder.create().build();
HttpGet httpGet = new HttpGet(link);
HttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
System.out.println(statusCode);
// 对200状态码进行处理
if (statusCode == HttpStatus.SC_OK) {
HttpEntity resEntity = response.getEntity();
// 获取页面数据并保存到文件
byte[] pageContent = EntityUtils.toByteArray(resEntity);
FileOutputStream fout = new FileOutputStream(outfile);
fout.write(pageContent);
System.out.println("获取网页成功!");
} else {
System.out.println("获取网页失败!");
}
}
}



