什么是网络:由点(计算机)和线(网线)构造的网状结构
什么是计算机网络:不同区域的计算机,通过线路连接能够实现数据传递与资源共享的方式
什么是网络编程:实现数据传递与资源共享的具体技术
概述:在实现通讯过程中的软硬件结合的操作
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:无连接的协议,不安全但效率高--例如:发短信
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 } }
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); } }
//案例:使用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); } }
//案例:多个客户端与服务器聊天 //服务器: //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); } }
//案例:注册功能 //分析: //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(); } } } }
/** * 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(); } } } }
//案例:聊天室程序 //分析: 多人聊天---多线程 //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); } } }