javaday17
目录
1 网络. 1
1.1 Socket 通信. 1
1.2 服务器端. 1
1.3 客户端. 1
1.4 超时. 1
练习1 网络. 1
1.5 阻塞操作. 1
1.6 服务器端的线程模型. 1
练习2 回声. 1
练习3 聊天室. 1
1 回顾
l HashMap
n key.hashCode() 得到哈希值,用哈希值来计算下标 i
n 键值对封装成 Enyry 实例放入 i 位置
u 空位置,直接放入
u 有数据,依次用key.equals()方法比较是否相等
l 找到相等的键,覆盖值
l 没有相等的键,用链表连接在一起
u 负载率,加载因子到0.75 (数据量/容量)
l 新建翻倍容量的新数组
l 所有数据重新执行哈希运算放入新数组
u jdk1.8
l 链表长度到8,把链表转成红黑树
l 树上的数据减少到6,转回成链表
2 网络
在物理网络的基础上,建立抽象的连接
win + r, 输入 cmd
输入命令:
ipconfig
ping 192.168.21.xxx
如果ping不通,要关闭防火墙
开始---搜索防火墙
2.1 Socket 通信
Socket - 插头
Socket - 网络套接字
l 通过 ip 地址,两台主机可以互相找到对象
l 在两台主机上,各选择一个端口号
n 端口是独占的
n 0到1024是一些常见服务的默认端口
u http 80
u https 443
u ftp 21
u ...
n 5万以后,是系统保留端口用,来自动分配
n 我们选择端口要选择 1024到5万之间的端口号
2.2 服务器端
被动等待客户端发起连接
ServerSocket 在服务器端,选择一个端口号, 在指定端口上等待客户端发起连接
ServerSocket ss = new ServerSocket(8000);
等待客户端发起连接,建立连接通道,并返回连接通道的服务器端插头对象
Socket s = ss.accept();
2.3 客户端
主动去连接服务器
Socket s = new Socket(ip, port);
取出双向的流
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
2.4 超时
socket.setSoTimeout(毫秒值)
设置接收数据,等待超时时长,超时会出现 SocketTimeoutException
练习1 网络
package day17;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server1 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(8000);
System.out.println(
"服务已经在 8000 端口上启动");
//暂停等待客户端发起连接
System.out.println("等待客户端连接");
Socket s = ss.accept();
System.out.println("客户端已连接");
//从插头对象,获取输入流和输出流
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
/*
* 通信协议,通信流程,数据格式
*
* 服务器端:
* 1. 接收 "hello"
* 2. 发送 "world"
*/
for (int i = 0; i < 5; i++) {
char c = (char) in.read();
System.out.print(c);
}
out.write("world".getBytes());
out.flush(); //刷出内存缓存
s.close();//断开连接
ss.close();//停止服务,释放端口
}
}
Client1
package day17;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client1 {
public static void main(String[] args) throws Exception {
Socket s = new Socket("旁边同学ip", 8000);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
/* 客户端:
* 1. 发送 "hello"
* 2. 接收 "world"
*/
out.write("hello".getBytes());
out.flush(); //刷出内存缓存
for (int i = 0; i < 5; i++) {
char c = (char) in.read();
System.out.print(c);
}
s.close();
}
}
2.5 阻塞操作
ss.accept()
暂停,等待客户端发起连接
in.read()
对方不发送数据,暂停,死等数据
2.6 服务器端的线程模型
练习2 回声
客户端发送到服务器的数据,原封不动的发回客户端
EchoServer
package day17;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class EchoServer {
public void launch() {
new Thread() {
@Override
public void run() {
try {
ServerSocket ss = new ServerSocket(8000);
System.out.println("服务已在 8000 端口上启动");
while(true) {
System.out.println("等待下一个客户端连接");
Socket s = ss.accept();
System.out.println("客户端已连接");
TongXinThread t = new TongXinThread(s);
t.start();
}
} catch (Exception e) {
System.out.println(
"无法在 8000 端口上启动服务,或服务已停止");
}
}
}.start();
}
class TongXinThread extends Thread {
Socket s;
public TongXinThread(Socket s) {
this.s = s;
}
@Override
public void run() {
/*
* 通信协议,流程和格式
* UTF-8编码的字符串,
* 每段字符串末尾添加换行
*
* BR--ISR--网络输入流
* PW--OSW--网络输出流
*/
try {
BufferedReader in =
new BufferedReader(
new InputStreamReader(
s.getInputStream(), "UTF-8"));
PrintWriter out =
new PrintWriter(
new OutputStreamWriter(
s.getOutputStream(),"UTF-8"));
String line;
while((line = in.readLine()) != null) {
out.println(line);
out.flush();
}
//断开
} catch (Exception e) {
//断开
}
System.out.println("一个客户端端已断开");
}
}
public static void main(String[] args) {
EchoServer s = new EchoServer();
s.launch();
}
}
EchoClient
package day17;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Scanner;
public class EchoClient {
public static void main(String[] args) throws Exception {
Socket s = new Socket("找一个人启动服务器", 8000);
BufferedReader in =
new BufferedReader(
new InputStreamReader(
s.getInputStream(), "UTF-8"));
PrintWriter out =
new PrintWriter(
new OutputStreamWriter(
s.getOutputStream(),"UTF-8"));
while(true) {
System.out.print("输入:");
String str = new Scanner(System.in).nextLine();
out.println(str);
out.flush();
String echo = in.readLine();
System.out.println("回声:"+echo);
System.out.println("-----------------");
}
}
}
练习3 聊天室
ChatServer
package day17;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class ChatServer {
private ArrayList<TongXinThread> list =
new ArrayList<>();
public void launch() {
//启动服务线程
new Thread() {
@Override
public void run() {
try {
ServerSocket ss = new ServerSocket(8000);
System.out.println("聊天室服务器已启动");
while(true) {
Socket s = ss.accept();
TongXinThread t =
new TongXinThread(s);
t.start();
}
} catch (Exception e) {
System.out.println(
"服务无法在 8000 端口上启动,或服务已经停止");
}
}
}.start();
}
class TongXinThread extends Thread {
Socket s;
BufferedReader in;
PrintWriter out;
private String name;
public TongXinThread(Socket s) {
this.s = s;
}
public void send(String msg) {
out.println(msg);
out.flush();
}
public void sendAll(String msg) {
synchronized (list) {
for (TongXinThread t : list) {
t.send(msg);
}
}
}
@Override
public void run() {
try {
//UTF-8, 换行
in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));
//接收客户端的昵称
this.name = in.readLine();
//把当前通信线程实例,加入集合
synchronized (list) {
list.add(this);
}
//发送欢迎信息
send("欢迎进入激情聊天室");
//群发上线消息
sendAll(name+"进入了聊天室,在线人数:"+list.size());
String line;
while((line = in.readLine()) != null) {
sendAll(name+"说:"+line);
}
//断开
} catch (Exception e) {
//断开
}
//删除当前通信线程实例
synchronized (list) {
list.remove(this);
}
//群发离线消息
sendAll(name+"离开了聊天室,在线人数:"+list.size());
}
}
public static void main(String[] args) {
ChatServer s = new ChatServer();
s.launch();
}
}
ChatClient
package day17;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Scanner;
public class ChatClient {
private Socket s;
private BufferedReader in;
private PrintWriter out;
private String name;
private LinkedList<String> list = new LinkedList<>();
private boolean flag; //开关
public void launch() {
try {
s = new Socket("192.168.21.61", 8000);
in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));
//昵称
System.out.print("起一个昵称: ");
name = new Scanner(System.in).nextLine();
out.println(name);
out.flush();
//接收线程
new Thread() {
@Override
public void run() {
receive();
}
}.start();
//输入线程
new Thread() {
@Override
public void run() {
input();
}
}.start();
//打印线程
new Thread() {
@Override
public void run() {
print();
}
}.start();
} catch (Exception e) {
System.out.println("无法连接聊天室服务器");
e.printStackTrace();
}
}
protected void print() {
while(true) {
synchronized (list) {
while (list.isEmpty() || flag) {
try {
list.wait();
} catch (InterruptedException e) {
}
}
String msg = list.removeFirst();
System.out.println(msg);
}
}
}
protected void input() {
System.out.println("按回车输入聊天内容");
while(true) {
new Scanner(System.in).nextLine();
flag = true;//打开开关
System.out.print("输入聊天内容:");
String s = new Scanner(System.in).nextLine();
out.println(s);
out.flush();
flag = false;//关闭开关
//通知打印线程可以继续打印
synchronized (list) {
list.notify();
}
}
}
protected void receive() {
try {
String line;
while((line = in.readLine()) != null) {
synchronized (list) {
list.add(line);
//通知打印线程已经有数据可以打印了
list.notify();
}
}
} catch (Exception e) {
}
System.out.println("已经与服务器断开连接");
}
public static void main(String[] args) {
ChatClient c = new ChatClient();
c.launch();
}
}