这里将自己学习java及其应用的一些笔记、积累分享一下,如果涉及到了文章、文字侵权,请联系我删除或调整。
一、网络
1.1 概述
- 查询本级网络基本情况
win + r,输入 cmd
输入命令:
ipconfig
- 尝试连接本局域网内的其他IP
ping 192.168.4.xxx
如果ping不通,关闭防火墙(注意在公开网络环境下,存在隐患)
1.2 Socket网络通信
- Socket 网络套接字
- 主机之间,需要能用 ip 地址,找到对方
- 在主机上选择一个端口,来插插头(Socket)
1.3 服务器端
- 在一个端口上启动服务
- 被动地等待客户端来发起连接
1.4 客户端
- 向指定服务器的 ip 地址和端口号,发起连接
- 建立连接通道
- 连接通道的两端,都有一个插头
1.5 ServerSocket类
- 启动服务,ServerSocket ss = new ServerSocket(8000);
端口必须独占
0到1024,是常见服务的默认端口
50000之后,系统保留端口用来动态分配
- 方法
accept()方法:
暂停,等待客户端发起连接;
建立与客户端的连接通道,并返回通道的服务器端插头对象。
close()方法:
停止服务,释放端口。
1.6 网络通信中的阻塞操作
- ServerSocketObject.accept()
阻塞,暂停等待客户端发起连接
- in.read(),对于Socket对象、ServerSocket对象均可获取InputStream对象
阻塞,接收数据,对方不发送,暂停死等数据
1.7 练习:服务器、客户端小案例
package 网络;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Sever_服务器测试 {
public static void main(String[] args) throws IOException {
// 9000端口上启动服务
ServerSocket ss = new ServerSocket(9000);
System.out.println("服务器已经在9000端口上启动服务!");
// 等待客户可发起连接
// 建立连接后,返回插头对象
Socket s = ss.accept();
System.out.println("客户端已连接");
// 从插头对象中取出“火线”,“零线”即输入流和输出流
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
/*
* 通信协议:通信流程、数据格式
* 第一步:接收“hello”;
* 第二部:发送“world”
* 数据格式为英文
*/
// 接收
for(int i = 0;i<5;i++) {
char c = (char) in.read();
System.out.print(c);
}
// 发送
out.write("world".getBytes());//getBytes()无参,默认将字符串转为系统默认编码方式
out.flush();// .flush()刷出本地内存中的缓存数据
s.close();// 完成数据交换,断开和客户端的连接“拔插头”
ss.close();// 停止服务,释放断口
}
}
package 网络;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Clinet_客户端 {
public static void main(String[] args) throws UnknownHostException, IOException {
// 向指定服务器的指定断口发起连接,IP地址请根据自己测试的环境修改
Socket s = new Socket("172.218.1.74", 9000);
// 从插头对象中取出火线,零线即输入流和输出流
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
/*
* 通信协议:通信流程、数据格式
* 第一步:发送“hello”;
* 第二部:接收“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();
}
}
1.8 服务器端的线程模型
1.8.1 练习:回声机
通过这个案例,我们尝试练习、熟悉一下服务器端的线程模型。需要说明的是,这只是一个用于熟悉相关知识点小案例,其中的异常处理还不完善,我们暂时忽略了这部分的内容。
package 回声服务器;
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() {// launch 启动、点火、发射
// 新建匿名类对象并调用start方法
new Thread() {
@Override
public void run() {
try {
//9000断口启动服务
ServerSocket ss = new ServerSocket(9000);
System.out.println("服务器已在9000断口启动服务!");
// 死循环,主机不停的接收新的连接请求并转给“通信”线程
while(true) {
Socket s = ss.accept();
System.out.println("一个客户端已上线!");
// 新创一个通信线程,将客户端转交给通信线程完成客户数据交流服务
// 主服务器循环至下一轮接收新的客户连接申请
TongXinThread t = new TongXinThread(s);
t.start();
}
} catch (Exception e) {
System.out.println("服务无法在9000客户端启动,或者服务异常停止!");
}
}
}.start();
}
// 内部类:通信线程
class TongXinThread extends Thread{
private Socket s;
// 获得主服务器传来的Socket对象,利用输入输出流通信
public TongXinThread(Socket socked) {
this.s = socked;
}
@Override
public void run() {// 涉及到数据流收发数据就有异常
try {
/* 通信协议
* 流程:while(true){收,发};
* 数据格式:字符串支持中文UTF-8,
* 每一行文本以换行符结尾;
* s.getInputStream 网络输入/输出流
* InputStreamReader 输入/输出编码转换流
* BufferedReader 使用readLine()方法
*/
BufferedReader in = new BufferedReader(// readLine
new InputStreamReader(// 字符串编码转化
s.getInputStream(),"UTF-8"));// 获取输入流
PrintWriter out = new PrintWriter(
new OutputStreamWriter(
s.getOutputStream(),"UTF-8"));
String line;
while((line = in.readLine())!= null) {// readLine可能抛异常
// System.out.println(line); 显示客户端发送的消息
out.println(line);// 必须有ln,以换行符分割
out.flush();
}
// TODO 网络正常断开,是null值,退出循环
} catch (Exception e) {
// TODO 网络异常断开
}
// 正常断开与异常断开统一处理
System.out.println("一个客户端断开!");
}
}
public static void main(String[] args) {
EchoServer s = new EchoServer();
s.launch();
}
}
package 回声服务器;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class EchoClinet {
public static void main(String[] args) throws IOException {
Socket s = new Socket("172.218.1.74",9000);
BufferedReader in = new BufferedReader(
new InputStreamReader(
s.getInputStream(),"UTF-8"));
PrintWriter out = new PrintWriter(
new OutputStreamWriter(
s.getOutputStream(),"UTF-8"));
while(true) {
System.out.println("请输入:");
String msg = new Scanner(System.in).nextLine();
out.println("用户输入:"+msg);
out.flush();
String r = in.readLine();
System.out.println("回声:"+r);
}
}
}
1.8.2 练习:Boss直聊
在上一个练习中,我们通过“回声”服务,基本了解了通信线程模型。在此,我们计划把这个模型再扩展一下,将其丰富为一个支持多人聊天的“群聊室”,这其中也会用到很多之前java学习中学到的内容。算是一个综合练习吧,毕竟温故而知新嘛 :),案例的详细细节,请大家看注释吧,在正文里就不再赘述了。
package Boss直聊;
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<ChatServer.TongXinThread>();
public void launch() {// launch 启动、点火、发射
// 新建匿名类对象并调用start方法
new Thread() {
@Override
public void run() {
try {
//9000断口启动服务
ServerSocket ss = new ServerSocket(9000);
System.out.println("服务器已在9000断口启动服务!");
// 死循环,主机不停的接收新的连接请求并转给“通信”线程
while(true) {
Socket s = ss.accept();
System.out.println("一个客户端已上线!");
// 新创一个通信线程,将客户端转交给通信线程完成客户数据交流服务
// 主服务器循环至下一轮接收新的客户连接申请
TongXinThread t = new TongXinThread(s);
t.start();
}
} catch (Exception e) {
System.out.println("服务无法在9000客户端启动,或者服务异常停止!");
}
}
}.start();
}
// 通信线程
class TongXinThread extends Thread{
private Socket s;
private BufferedReader in;
private PrintWriter out;
private String name;
public TongXinThread(Socket socket) {
this.s = socket;
}
// 私聊
public void send(String msg) {
out.println(msg);
out.flush();
}
// 群聊
public void sendAll(String msg) {
for(TongXinThread t : list) {
t.send(msg);
}
}
@Override
public void run() {
try {
this.in = new BufferedReader(// readLine
new InputStreamReader(// 字符串编码转化
s.getInputStream(),"UTF-8"));// 获取输入流
this.out = new PrintWriter(
new OutputStreamWriter(
s.getOutputStream(),"UTF-8"));
// 1接收客户端昵称
this.name = in.readLine();
// 2给当前客户端发送“欢迎”
send(this.name+"欢迎你进入激情聊天室!");
// 3把当前通信对象加入list
list.add(this);// 进入“群”,则可以接收到群聊信息
// 4群发客户上线消息
sendAll(this.name+"已经进入了聊天室!");
// 群聊,广播客户发送的消息
String line;
while((line =in.readLine())!=null) {
sendAll(this.name+"说:");
}
// TODO 用户(网络)正常断开,是null值,退出循环
} catch (Exception e) {
// TODO 用户(网络)异常断开
}
// 统一处理异常
// 断开连接:将当前对象移除list
list.remove(this);
sendAll(this.name+"离开了聊天室");
}
}
public static void main(String[] args) {
ChatServer s = new ChatServer();
s.launch();
}
}
package Boss直聊;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class ChatClient {
private Socket s;
private BufferedReader in;
private PrintWriter out;
private String name;
public void launch() {
try {
// 博友在测试时,请注意更换为自己ChatSever的IP和端口
this.s = new Socket("172.218.1.74", 9000);
this.in = new BufferedReader(// readLine
new InputStreamReader(// 字符串编码转化
s.getInputStream(), "UTF-8"));// 获取输入流
this.out = new PrintWriter(
new OutputStreamWriter(
s.getOutputStream(), "UTF-8"));
// 起个昵称并发送至服务器
System.out.println("昵称:");
this.name = new Scanner(System.in).nextLine();
out.println(this.name);
out.flush();
// 因为接收信息与循环读入用户输入信息是阻塞的,所以用两个线程并行执行
// 接收线程(匿名内部类),接收聊天室的信息
new Thread() {
@Override
public void run() {
receive();
}
}.start();
// 输入线程,用户输入欲发送的信息
new Thread() {
@Override
public void run() {
input();
}
}.start();
} catch (Exception e) {
System.out.println("无法链接服务器!");
}
}
protected void input() {
while(true) {
System.out.println("输入聊天内容=>");
String s = new Scanner(System.in).nextLine();
out.println(s);// 必须加ln
out.flush();
}
}
protected void receive() {
// 接收数据有异常
try {
String line;
while((line = in.readLine())!=null) {
System.out.println(line);
}
// TODO 用户(网络)正常断开,是null值,退出循环
} catch (Exception e) {
// TODO 用户(网络)异常断开
}
// 统一处理异常,断开连接
System.out.println("已经与服务器断开连接!");
}
public static void main(String[] args) {
ChatClient c = new ChatClient();
c.launch();
}
}