CS架构和BS架构
这两个架构是现在市面上主流的两个架构,CS架构主要是客户端+服务器,而BS架构主要是网页+服务器。BS架构的优点是方便,所有数据通过服务器传输,缺点也很明显,由于所有数据都是通过网络传输,导致BS架构里面的数据不能过多,否则则会导致用户由于网络问题出现卡顿的情况。而CS架构的优点就是将大量的基础信息例如音乐,图片放入客户端让用户下载到本地中,网络只传送一些数据,就会使用户在使用时不用考虑数据大小的问题,缺点就是需要将客户端下载到本地,不方便。
网络编程的三要素(IP,端口号,协议)
双方各自的IP地址:设备在网络中的地址
使用传输软件的端口号:一个软件对应一个端口号,只有端口号相同才能进行数据传输(也就是双方都只使用一个软件才能进行数据交流,例如都使用微信才能相互交流)
网络传输规则:数据在网络中传递的规则如:TCP,https等
IP以及主机名的获取
通过InetAddress类里面的静态方法getbyName方法能通过传入的主机名或者IP查找到对应的IP地址。
通过InetAddress实例化对象调用getHostName方法能通过传入的IP得到对应的主机名,但是如果传入的IP不在局域网内,则会返回IP而不是主机名。
通过调用InetAddress实例化对象调用getHostAddress方法能得到对应主机的IP地址
上述具体实现如下:
package com.itazhang.Demo1;import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;public class MyIntaddressDemo1 {public static void main(String[] args) throws UnknownHostException {//可以通过主机名和ip地址查找到IpInetAddress address = InetAddress.getByName("192.168.0.100");System.out.println(address);//使用IP地址得打主机名,如果局域网内没有这台电脑就会返回IP地址String name = address.getHostName();System.out.println(name);//查看ipString hostAddress = address.getHostAddress();System.out.println(hostAddress);}
}
端口号
网络通信协议
UDP协议:UDP协议是面向无连接的传输协议,他在传输数据时不会检查目的地与发送地网络是否联通,会直接将数据发送过去,且一次传输有大小限制,优点为传输快,缺点为数据在传输过程中易丢失,数据不安全
TCP协议:TCP协议是面向连接的通信协议,在传输之前会坚持发送地和目的地的网络是否连接,如果连接,才会将数据发送,且一次传输没有大小限制,优点为数据传输安全,不丢失,缺点为传 输数据的速度慢。
UDP通信协议
UDP的传输数据主要包括以下几个步骤
1、创建用来传输数据的对象
//创建发送数据的对象 DatagramSocket ds = new DatagramSocket();
2、将需要传输的数据打包成字节数组
String str = "我是测试消息"; //将需要发送的数据转化为字节数组 byte[] bytes = str.getBytes();
3、找到自己需要发送的地址
//创建需要发送的地址 InetAddress address = InetAddress.getByName("127.0.0.1");
4、写出发送到对方的端口
//创建发送数据的端口号 int port = 10086;
5、将上述信息传入数据打包的对象,将数据打包
传递参数格式(需要传输的数据转化成的字节数组,需要传输的长度,目的IP,传输的端口号)
//对数据进行打包加工 DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
6、传输数据,释放资源
ds.send(dp); ds.close();
UDP的接收数据主要包括以下几个步骤
1、创建接收数据的对象,也是DatagramSocket,其中传入接收的端口
//创建接收对象 DatagramSocket ds = new DatagramSocket(10086);
2、创建对象用来接收数据,也是用字节数组的方式接收
byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes,bytes.length); ds.receive(dp);
3、解析数据,可以用dp调用各种属性的get方法解析数据,将传递过来的字节数组转化为相应的类型
//解析数据包 InetAddress address = dp.getAddress(); int port = dp.getPort();
4、打印数据,释放资源,是将上述转化类型的代码放到打印方法中的
//打印输出,释放资源 System.out.println("是从地址为"+address+"端口号为"+port+"的电脑发出的数据:"+new String(bytes,0,bytes.length)); ds.close();
一个利用上述传输接收方法实现的简易聊天室
实现一个简易聊天室,输入端输入886结束输入,接收端无限循环接收,最后手动关闭
接收端实现如下:
package com.itazhang.Demo2;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;public class GetMessageDemo2 {public static void main(String[] args) throws IOException {//创建接收对象DatagramSocket ds =new DatagramSocket(10086);//创建数据包接收数据byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes,bytes.length);while (true){ds.receive(dp);InetAddress address = dp.getAddress();int port = dp.getPort();String s = new String(bytes, 0, bytes.length);//将数据解析并打印System.out.println("这是从地址为"+address+"端口号为"+port+"的数据"+s);}}
}
发送端实现如下:
package com.itazhang.Demo2;import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;public class SendMessageDemo2 {public static void main(String[] args) throws IOException {//创建发送对象DatagramSocket ds = new DatagramSocket();Scanner sc = new Scanner(System.in);while(true){System.out.println("请输入你想要发送的数据:");String s = sc.nextLine();if(s.equals("886")){break;}else {//打包数据byte[] bytes = s.getBytes();InetAddress address = InetAddress.getByName("127.0.0.1");int port = 10086;//发送数据DatagramPacket dp = new DatagramPacket(bytes, bytes.length,address,port);ds.send(dp);}}//释放资源ds.close();}
}
三种发送方式,单播,组播,广播
TCP通信协议
tcp通信协议在传输时是通过客户端发送,服务端接收这个特点进行通信的。
客户端发送数据步骤为:创建Socket发送对象,在创建时传入要发送到的IP和端口号,利用Socket对象获取输出流,再通过输出流将数据发出,实现代码如下:
package com.itazhang.Demo3;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;public class Client {public static void main(String[] args) throws IOException {//创建socket对象,并传入需要连接的Ip地址和端口Socket socket = new Socket("127.0.0.1",10086);//通过对象获取到输出流OutputStream os = socket.getOutputStream();//通过输出流的write方法将数据传输os.write("abcabc".getBytes());//释放资源os.close();socket.close();}
}
服务端接收数据步骤如下:创建ServerSocket接收对象,创建该对象的时候传入接收的端口号,然后通过该接收对象调用输入流,再通过输入流的read方法读取到数据,并将数据转化为对应的类型,最后释放资源,实现TCP通信,实现代码如下:
(因为默认中文为三个字节,但下列代码是将字节一个一个的读取并转换,所以如果用下列方法读取中文数据的话会显示乱码,如果要实现对中文的传输以及阅读,需要将下列代码中的字节输入流用转换流转换,即字符输入流,这样就不会出现一个字符一个字符的读取,也就可以传输中文)
package com.itazhang.Demo3;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {ServerSocket ss = new ServerSocket(10086);Socket socket = ss.accept();InputStream is = socket.getInputStream();int temp;while (true){temp = is.read();if(temp == -1){break;}else{System.out.println((char)temp);}}is.close();ss.close();}
}
TCP通信协议练习
实现一个可以多次发送数据的聊天室,能发中文,且能被接收
客户端(发送),在发送数据时,因为需要接受中文的缘故,所以采用了缓冲输出流的方法,这种方法只会在缓冲区放慢或者关闭缓冲区才会发送数据,所以需要在每次发送数据时调用flush方法刷新缓冲区,让每一次输入数据都直接发送过去
package com.itazhang.TCPDemo4;import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;public class Exercise1Client {public static void main(String[] args) throws IOException {Socket socket = new Socket("127.0.0.1",10086);OutputStream os = socket.getOutputStream();BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));Scanner sc = new Scanner(System.in);while(true){System.out.println("请输入你想传输的话");String s = sc.nextLine();if("886".equals(s)){break;}else{bw.write(s);bw.newLine();bw.flush();}}}
}
服务端(接收)
package com.itazhang.TCPDemo4;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class Exercise1Server {public static void main(String[] args) throws IOException {ServerSocket ss = new ServerSocket(10086);Socket socket = ss.accept();BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String s;while(true){s = br.readLine();if(s == null){break;}else{System.out.println(s);}}socket.close();ss.close();}
}
练习(一)
使用TCP进行文本文件传输,文件里可能有中文
分析:先将文件的数据读取出,再将其传输,在客户端先接收数据,再将数据写入文件,因为有可能文件中有中文,所以得用转换流将字节流转换(记得关流)
客户端实现如下:
package com.itazhang.TCPExercise3;import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.ArrayList;public class Client {public static void main(String[] args) throws IOException {FileReader fr = new FileReader("D:\\11Codingtext\\MySocketnet\\a.txt");ArrayList<Integer> list = new ArrayList<>();int temp;while (true){temp = fr.read();if(temp==-1){break;}else{list.add(temp);}}Socket socket = new Socket("127.0.0.1",10086);OutputStream os = socket.getOutputStream();OutputStreamWriter osw = new OutputStreamWriter(os);for (Integer integer : list) {osw.write(integer);}osw.close();socket.close();fr.close();}
}
服务端实现如下:
package com.itazhang.TCPExercise3;import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;public class Server {public static void main(String[] args) throws IOException {ServerSocket ss = new ServerSocket(10086);Socket socket = ss.accept();InputStream is = socket.getInputStream();InputStreamReader isr = new InputStreamReader(is);FileWriter fw = new FileWriter("D:\\11Codingtext\\MySocketnet\\b.txt");int temp;while(true){temp = isr.read();if(temp == -1){break;}else{fw.write(temp);}}fw.close();ss.close();}
}
练习(二)
使用TCP协议进行图片文件传输(图片只能使用字节流)
客户端
package com.itazhang.Demo5;import java.io.*;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {//创建套接字,输出文件流Socket socket = new Socket("127.0.0.1",10086);OutputStream os = socket.getOutputStream();BufferedOutputStream bos = new BufferedOutputStream(os);//读取本地文件数据BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\11Codingtext\\MySocketnet\\maomao.jpg"));int temp;byte[] bytes = new byte[1024];while(true){temp = bis.read(bytes);if(temp == -1){break;}else {bos.write(bytes,0,temp);}}bos.flush();socket.close();bis.close();}}
服务端
package com.itazhang.Demo5;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {//创建套接字,创建接收输入流ServerSocket ss = new ServerSocket(10086);Socket socket = ss.accept();InputStream is = socket.getInputStream();BufferedInputStream bis = new BufferedInputStream(is);//创建输出流,将读取的文件写入新文件byte[] bytes = new byte[1024];int temp;BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\11Codingtext\\MySocketnet\\temp.jpg"));while(true){temp = bis.read(bytes);if(temp == -1){break;}else{bos.write(bytes,0,temp);}}bos.flush();ss.close();bos.close();}
}
练习(二)(重点掌握)
要求多线程实现图片的传输,每个线程创建并开启之后会出现对应的一个新的jpg文件,例如第一个线程开启为1.jpg,第二个开启就是生成2.jpg。
线程类代码如下:通过构造方法,将每一次 开启线程后,所需要传输的socket套接字传输给Myrunnable这个类
package com.itazhang.Demo5;import java.io.*;
import java.net.Socket;public class MyRunnable implements Runnable{Socket socket;static int count = 1;public MyRunnable(Socket socket) {this.socket = socket;}@Overridepublic void run() {InputStream is = null;try {is = socket.getInputStream();} catch (IOException e) {e.printStackTrace();}BufferedInputStream bis = new BufferedInputStream(is);//创建输出流,将读取的文件写入新文件byte[] bytes = new byte[1024];int temp;BufferedOutputStream bos = null;synchronized (MyRunnable.class){try {bos = new BufferedOutputStream(new FileOutputStream("D:\\11Codingtext\\MySocketnet\\" +count+ ".jpg"));count++;} catch (FileNotFoundException e) {e.printStackTrace();}}while(true){try {if (!((temp = bis.read(bytes))!=-1)) break;bos.write(bytes,0,temp);} catch (IOException e) {e.printStackTrace();}}try {bos.flush();} catch (IOException e) {e.printStackTrace();}try {bos.close();} catch (IOException e) {e.printStackTrace();}}
}
服务端代码实现如下:下面每开启一个线程对应一个用户
package com.itazhang.Demo5;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {//创建套接字,创建接收输入流ServerSocket ss = new ServerSocket(10086);while (true){Socket socket = ss.accept();//开启线程,一个用户对应一条线程new Thread(new MyRunnable(socket)).start();new Thread(new MyRunnable(socket)).start();new Thread(new MyRunnable(socket)).start();new Thread(new MyRunnable(socket)).start();}}
}
客户端代码如下:
package com.itazhang.Demo5;import java.io.*;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {//创建套接字,输出文件流Socket socket = new Socket("127.0.0.1",10086);OutputStream os = socket.getOutputStream();BufferedOutputStream bos = new BufferedOutputStream(os);//读取本地文件数据BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\11Codingtext\\MySocketnet\\maomao.jpg"));int temp;byte[] bytes = new byte[1024];while(true){temp = bis.read(bytes);if(temp == -1){break;}else {bos.write(bytes,0,temp);}}bos.flush();socket.close();bis.close();}}