1.计算机网络
1.1概述
什么是网络:由点(计算机)和线(网线)构造的网状结构
什么是计算机网络:不同区域的计算机,通过线路连接能够实现数据传递与资源共享的方式
什么是网络编程:实现数据传递与资源共享的具体技术
1.2网络模型
概述:在实现通讯过程中的软硬件结合的操作
1.3网络编程三要素
IP地址:
计算机的唯一标识
有两种IP地址表示:
IPV4:分4个段,每个段最高为255;例如:192.168.1.6
IPV6:分8个段,每个段最高位FFFF;(十六进制)IPV4分类:
A类:从1开始~126段
B类:127开始~191段
C类:192开始~223段(10个以内)
D类:224开始~239段回环地址:127.0.0.1,代表本机测试地址
Port:
通讯软件的唯一识别:(0~65535)
0~1024: 系统已经分配或保留的端口,一般不去使用
1024以后可以使用
避开一些常用端口:例如3306,8080,1521等协议:
TCP,UDP协议
TCP:面向连接的协议,安全但效率低--例如:打电话
UDP:无连接的协议,不安全但效率高--例如:发短信
2.网络编程
2.1INetAddress类
INetAddress类: 代表IP地址对象的类
可以调用相关方法得到IP地址
public class Test1 {
public static void main(String[] args) throws UnknownHostException {
//通过ip或主机名或域名得到ip对象
InetAddress net1 = InetAddress.getByName("192.168.1.8");
System.out.println(net1);
//一个域名可能绑定多台服务器(多个IP)
InetAddress[] nets = InetAddress.getAllByName("www.baidu.com");
System.out.println(Arrays.toString(nets));
InetAddress net2 = InetAddress.getLocalHost();
System.out.println(net2); //获取本机IP
}
}
2.2TCP-客户端发数据到服务器
TCP编程:也叫做Socket编程,基于tcp协议的字节流的传输协议
通讯模型: 客户端-服务器模型
服务器:
1.实例化服务器Socket对象,指定自身端口
2.监听客户端的连接,如果有客户端连接了,那么创建一个socket与客户端通讯客户端:
1.实例化socket对象,传入服务器的ip和端口谁先启动? 服务器先启动,有监听阻塞方法
//案例:服务器与客户端建立TCP连接后,进行通讯;
//客户端给服务器发数据,服务器也可以给客户端发数据
public class Server {
public static void main(String[] args) throws IOException {
//实例化服务器socket,指定自身端口
ServerSocket serverSocket = new ServerSocket(9527);
//调用accept监听客户端连接,如果有客户端连接了,则创建了socket对象与客户端通讯
Socket socket = serverSocket.accept(); //阻塞方法
System.out.println("有一个客户端连上来了");
//接收数据--读
InputStream is = socket.getInputStream();
byte[] b = new byte[1024];
int len = is.read(b);
System.out.println(new String(b, 0,len));
//服务器发送数据--写
OutputStream os = socket.getOutputStream();
os.write("服务器回应给客户端的数据".getBytes());
IOUtils.closeAll(is,os,socket,serverSocket);
}
}
-----Client-------
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1", 9527);
//通过字节流发数据--写
OutputStream os = socket.getOutputStream();
os.write("客户端发送的数据..".getBytes());
//客户端的接收--读
InputStream is = socket.getInputStream();
byte[] b = new byte[1024];
int len = is.read(b);
System.out.println(new String(b, 0,len));
//统一资源关闭: 先关小的,再关大的
IOUtils.closeAll(os,is,socket);
}
}
2.3客户端上传图片到服务器
//案例:使用tcp编程实现图片上传到服务器
//分析:先在客户端通过输入字节流读取图片资源,然后写到socket中
//在服务器的socket中通过读字节流接收,然后再写到服务器本地
-------Server--------
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086);
Socket socket = ss.accept();
//从socket中读取字节流
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("d:\\a.jpg");
byte[] b = new byte[1024];
int len;
while((len=is.read(b))!=-1) {
fos.write(b, 0, len);
}
System.out.println("服务器接收成功~!");
IOUtils.closeAll(fos,is,socket,ss);
}
}
-------Client--------
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1", 10086);
//客户端从图片中读取资源
FileInputStream fis = new FileInputStream("b.jpg");
byte[] b = new byte[1024];
int len;
OutputStream os = socket.getOutputStream();
while((len=fis.read(b))!=-1) {
os.write(b, 0, len);
}
System.out.println("上传到服务器~~");
IOUtils.closeAll(os,fis,socket);
}
}
2.4多个客户端发数据给服务器
//案例:多个客户端与服务器聊天
//服务器:
//1.来一个客户端,那么产生一个socket与客户端通讯---多线程
//2.从socket总接收文本内容,通过字符缓冲流封装
//客户端:
//1.循环从客户端录入数据
------服务器------
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10010);
//死循环实时监听客户端连接
while(true) {
Socket socket = ss.accept();
System.out.println("有一个客户端进行了连接...");
new ServerThread(socket).start();//在开辟的路径中,执行socket操作
}
}
}
------服务器线程------
public class ServerThread extends Thread {
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
InputStream is = null;
BufferedReader br = null;
try {
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
while(true) {
String msg = br.readLine();
System.out.println(msg);
if(msg.equals("886")) {
break;
}
}
} catch (IOException e) {
System.out.println("有异常中断。。。");
}finally {
System.out.println("有一个客户端退出了连接");
IOUtils.closeAll(is,br,socket);
}
}
}
------客户端------
public class Clent {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1", 10010);
System.out.println("请从客户端进行录入:");
OutputStream os = socket.getOutputStream(); //字符缓冲流包装
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
//从键盘录入
Scanner sc = new Scanner(System.in);
while(true) {
String msg = sc.next();
bw.write(msg);
bw.newLine(); //换行
bw.flush(); //刷新
if(msg.equals("886")) { //约定
break;
}
}
IOUtils.closeAll(os,bw,socket);
}
}
3.网络编程案例
3.1注册功能
//案例:注册功能
//分析:
//1.客户端与服务器建立连接
//2.客户端准备好注册数据,拼成一个字符串;例如:{id:"1001",name:"zs",age:30}
//3.发送注册数据,服务器接收数据
//4.服务器拆分数据,取出id对应的value作为key,接收的注册信息作为value
//5.判断key在配置文件中是否存在,如果存在,则返回"已存在"
//6.不存在,把这些数据存到配置文件,并返回“注册成功”
-----服务器------
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9527);
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String msg = br.readLine(); //{id:1001,name:zs,age:30}
String strId = msg.split(",")[0]; //{id:1001
String id = strId.split(":")[1]; //1001
//通过Properties集合去加载配置文件
Properties p = new Properties();
p.load(new FileInputStream("user.properties"));
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
if(p.containsKey(id)) {
bw.write("已存在");
}else {
Tool.saveProperties(id,msg); //将数据存储到配置文件
bw.write("注册成功");
}
bw.newLine();
bw.flush();
IOUtils.closeAll(bw,os,br,is,socket);
}
}
-----客户端------
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",9527);
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
String json = getData(); //{id:1001,name:zs,age:30}
//发数据
bw.write(json);
bw.newLine();
bw.flush();
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String msg = br.readLine();
System.out.println("服务器响应:"+msg);
IOUtils.closeAll(is,br,os,bw,socket);
}
private static String getData() {
Scanner sc = new Scanner(System.in);
System.out.println("请输入ID:");
String id = sc.next();
System.out.println("请输入用户名:");
String name = sc.next();
System.out.println("请输入年龄:");
int age = sc.nextInt();
return "{id:"+id+",name:"+name+",age:"+age+"}";
}
}
----user.properties在src目录下建一个----
----工具类----
public class Tool {
public static void saveProperties(String id, String msg) throws FileNotFoundException, IOException {
Properties properties = new Properties();
properties.put(id, msg);
properties.store(new FileOutputStream("user.properties"), "");
}
}
----------CloseAll------
public class CloseAll {
public static void closeAll(Closeable... closeable) throws IOException {
if(closeable!=null) {
for (Closeable c: closeable) {
c.close();
}
}
}
}
3.2登录功能
/**
* 1. 用户登录:
客户端:
输入ID,name;并拼接成字符串,例如“{id:1001,name:zs}”
将该字符串传到服务器;
服务器:
在服务器中根据拆分的id值去匹配配置文件user.properties中是否存在key为1001的值
如果有则取出value,拆分出name的值;和传过来的json数据里面的id和name比较
匹配成功则返回“登录成功”到客户端;如果不匹配,则返回“登录失败”到客户端
* */
-----------Client---------------
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1",9090);
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
String json = getData(); //{id:1001,name:zs,age:30}
//发数据
bw.write(json);
bw.newLine();
bw.flush();
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String msg = br.readLine();
System.out.println("服务器响应:"+msg);
OutputStream osa=socket.getOutputStream();
BufferedWriter bwa = new BufferedWriter(new OutputStreamWriter(osa));
System.out.println("=====登录界面======");
//登录
String jsons = getlogin();
//发登录的数据给服务器
bwa.write(jsons);
bwa.newLine();
bwa.flush();
System.out.println(br.readLine());
CloseAll.closeAll(is,br,bw,os,osa,bwa,socket);
}
private static String getlogin() {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名(ID):");
String id = scanner.next();
System.out.println("请输入姓名(name):");
String name = scanner.next();
return "id:"+id+",name:"+name+"";
}
private static String getData() {
Scanner sc=new Scanner(System.in);
System.out.println("请输入ID:");
String id=sc.next();
System.out.println("请输入用户名:");
String name=sc.next();
System.out.println("请输入年龄:");
int age=sc.nextInt();
return "id:"+id+",name:"+name+",age:"+age;
}
}
---------------Server------------------
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9090);
Socket socket = ss.accept();
//接受客户端的数据,并且剪切数据
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String msg = br.readLine();
String strId = msg.split(",")[0];
String id = msg.split(":")[1];
//对文件进行加载(读取内部文件)
Properties pro = new Properties();
pro.load(new FileInputStream("users.properities"));
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
if(pro.containsKey(id)) {
System.out.println("已经存在");
}else {
Tools.saveProperities(msg);
bw.write("注册成功");
}
bw.newLine();
bw.flush();
//接受客户端的数据,并且剪切
InputStream isa = socket.getInputStream();
BufferedReader bra = new BufferedReader(new InputStreamReader(isa));
String msgs = bra.readLine();
//先剪切用户名
String strIds = msgs.split(",")[0];
String ids = strIds.split(":")[1];
//剪切密码
String strName = msgs.split(",")[1];
String name=strName.split(":")[1];
//读取内部文件
Properties p = new Properties();
p.load(new FileInputStream("users.properities"));
//将获取客户端的数据,对文件剪切的内容进行比对
OutputStream osa = socket.getOutputStream();
BufferedWriter bwa = new BufferedWriter(new OutputStreamWriter(osa));
if(p.containsKey("id")&&p.containsKey("name")) {
bw.write("登陆成功!");
}else {
bw.write("您输入的用户名或姓名有误!");
}
CloseAll.closeAll(bw,os,br,is,isa,bra,osa,bwa,socket);
}
}
----------------工具类-------------------
public class Tools {
public static void saveProperities(String msg) throws FileNotFoundException, IOException {
Properties pro = new Properties();
String[] str = msg.split(",");
for(int i =0;i<str.length;i++) {
String[] str1 = str[i].split(":");
pro.put(str1[0], str1[1]);
}
pro.store(new FileOutputStream("users.properities"),"");
}
}
-------------------CloseAll-------------------
public class CloseAll {
public static void closeAll(Closeable... closeable) throws IOException {
if(closeable!=null) {
for (Closeable c: closeable) {
c.close();
}
}
}
}
3.3聊天室程序
//案例:聊天室程序
//分析: 多人聊天---多线程
//1.通过多线程形式接收多个客户端的连接
//2.客户端要录入姓名,传入服务器接收,并存储到线程中
//(注意:客户端的发送和接收要分为两个线程,才能方便群发)
//3.服务器给客户端回应“欢迎进入聊天室”
//4.该客户端就可以实时发数据聊天了
//5.要实现服务器群发信息给客户端,需要先将所有线程对象存储
//6.退出方式,客户端退出,其他用户应该都知道
-------服务器-------
public class Server {
public static List<ServerThread> list = new ArrayList<ServerThread>();
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9527);
//多线程方式监听及创建socket
while(true) {
Socket socket = ss.accept();
System.out.println("有一个客户端进来了");
ServerThread st = new ServerThread(socket);
st.start();
list.add(st); //存储线程对象
}
}
}
------服务器线程-------
public class ServerThread extends Thread {
private Socket socket;
private BufferedReader br;
private BufferedWriter bw;
public ServerThread(Socket socket) throws IOException {
this.socket = socket;
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
}
@Override
public void run() {
try {
sendHello(); //欢迎
while(true){
String name = this.br.readLine(); //读取到数据后,发给自身
String msg = this.getName()+"说:"+name;
//循环遍历线程对象,除了自己,都发一份出去
for(ServerThread st : Server.list) {
if(st!=this) {
st.bw.write(msg);
st.bw.newLine();
st.bw.flush();
}
}
}
} catch (Exception e) {
String msg = this.getName()+"退出了聊天室"; //群发退出信息
Server.list.remove(this); //将当前线程对象在集合中移除
for(ServerThread st : Server.list) { //移除后群发
try {
st.bw.write(msg);
st.bw.newLine();
st.bw.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}finally {
IOUtils.closeAll(bw,br,socket);
}
}
private void sendHello() throws IOException {
String name = br.readLine(); //读取到数据后,发给自身
String msg = "【温馨提示】:欢迎"+name+"进入聊天室";
this.setName(name); //记录客户的访问
bw.write(msg);
bw.newLine();
bw.flush();
}
}
------客户端-------
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",9527);
//客户端读写分离
new WriteClient(socket).start();
new ReadClient(socket).start();
}
}
-------客户端写线程-------
public class WriteClient extends Thread {
private Socket socket;
public WriteClient(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
OutputStream os = null;
BufferedWriter bw = null;
try {
os = socket.getOutputStream();
bw = new BufferedWriter(new OutputStreamWriter(os));
System.out.println("请输入用户名:");
Scanner sc = new Scanner(System.in);
while(true) {
String name = sc.next(); //第一次是输入名字,后面就是聊天内容
bw.write(name);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
IOUtils.closeAll(os,bw,socket);
}
}
}
-------客户端读线程--------
public class ReadClient extends Thread {
private Socket socket;
public ReadClient(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
InputStream is = null;
BufferedReader br = null;
try {
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
while(true) {
String msg = br.readLine();
System.out.println(msg);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
IOUtils.closeAll(is,br,socket);
}
}
}