网络编程基础
参考文章:https://www.cnblogs.com/swordfall/p/10781281.html
整理总结:
IOS模型
TCP/IP模型
模型及其对应层次的协议即作用
IP协议
TCP协议
UDP协议
HTTP协议
HTTPS协议
Socket
Socket,实际上是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
Socket的出现,只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口,比如create、listen、accept、send、read和write等等。
解决问题:主要解决如何包装数据
HTTP协议实现代码实例
普通流传输
Client:
- 构建TCP协议实现类对象socket,方便按照TCP协议建立连接
- 实现socket,让socket有实际意义,只需要将IP和端口就能确定本线程的目标
- 从socket那里构建一个输出流,方便数据写入输出流
- 将数据写入输出流后,关闭输出流,再关闭socket
Server: - 通过给ServerSocket对象赋值,开启端口,以便接收数据
- ServerSocket对象可以接收从端口得到传来的Socket对象A
- 然后可以从A中获得到输入流,再从输入流中获取数据(定义输出流来输出输入流中的数据)
- 关闭输出流,再关闭输入流,最后关闭socket和serverSocket
public class Client {
public static void main(String[] args) {
client();
}
public static void client(){
OutputStream output = null;
Socket socket = null;
try {
InetAddress localHost = InetAddress.getByName("127.0.0.1");
socket = new Socket(localHost,8848);
output = socket.getOutputStream();
output.write("hello I'm the client".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(output != null){
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class Server {
public static void main(String[] args) {
server();
}
public static void server() {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream input = null;
ByteArrayOutputStream out = null;
try {
serverSocket = new ServerSocket(8848);
socket = serverSocket.accept();
System.out.println("client IP: " + socket.getInetAddress());
input = socket.getInputStream();
/*
一般不建议这样书写,数据传输时可能会出现乱码!!
byte[] buffer = new byte[1024];
int len;
while((len = input.read(buffer)) != -1){
String data = new String(buffer,0,len);
System.out.println(data);
}*/
out = new ByteArrayOutputStream();
byte[] buffer = new byte[10];
int len;
while((len = input.read(buffer)) != -1){
out.write(buffer,0,len);
}
System.out.println(out.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(input != null){
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(serverSocket != null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
文件流传输
Client:将文件传递给服务器
- 创建文件,得到文件用来创建文件流
- 定义socket,设定socket的ip,port,输出流
- 通过输入流将文件流放入socket的输出流中
- 传递完毕后,关闭输入流,在关闭输出流,最后关闭socket
Server:收到文件将其保存在本地文件中 - 创建ServerSocket,指定端口后可以通过SereverSocket获得这个端口传来的Socket
- 获得到Socket后,去得到里面的输入流
- 建立文件输出流来获得Socket的输入流
- 关闭文件输出流,再关闭socket中的输入流,然后关闭socket对象,最后关闭serverScoket
public class TcpClientDemo02 {
public static void main(String[] args) throws Exception {
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9000);
OutputStream os = socket.getOutputStream();
File file = new File("src/web_study_lession2/asd.jpg");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
byte[] buffer = new byte[1024];
int len;
while((len = bis.read(buffer))!= -1) {
os.write(buffer,0,len);
}
bis.close();
os.close();
socket.close();
}
}
public class TcpSeverDemo02 {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(9000);
System.out.println("已经打开端口9000,等待客服端连接");
Socket accept = serverSocket.accept();//阻塞式监听,会一直监听,直到监听到
System.out.println("连接客服端的IP:"+accept.getInetAddress());
InputStream is = accept.getInputStream();
File receive = new File("receive.txt");
if(!receive.exists()){
receive.createNewFile();
}
FileOutputStream fos = new FileOutputStream(receive);
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer))!= -1) {
fos.write(buffer, 0, len);
}
fos.close();
is.close();
accept.close();
serverSocket.close();
}
}
UDP协议实现代码实例
客服端将数据报发送到服务端
服务端:
1.打开端口
2.接收数据包
3.处理数据包
4.关闭连接
public class UdpServerDemo {
public static void main(String[] args) throws Exception {
//开放端口
DatagramSocket socket = new DatagramSocket(9090);
// 接收数据
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);
//关闭连接
socket.close();
//输出包中内容
System.out.println(packet.getAddress().getHostAddress());
System.out.println(new String(packet.getData(),0, packet.getLength()));
}
}
服务端:
1.确定目标(ip和端口)
2.建立包
3.发送包
public class UdpClientDemo {
public static void main(String[] args) throws Exception {
//建立socket通信
DatagramSocket socket = new DatagramSocket();
//建立包
String msg = "nihao";
InetAddress localhost = InetAddress.getByName("localhost");
int port = 9090;
DatagramPacket packet = new DatagramPacket(msg.getBytes(),0, msg.getBytes().length, localhost, port);
//发送包
socket.send(packet);
}
}
通过url下载数据
1.创建url
2.通过url获得连接
3.在连接上获得输入流
4.创建自己的输出流用来输出文件
5.将输入流转化为输出流
6.关闭输出流,输入流,连接
public class UrlDown {
public static void main(String[] args) throws Exception {
URL url = new URL("https://m801.music.126.net/20210503215010/1395364ef0339e371ea7b50e104ba131/jdyyaac/025e/540b/5408/54ea83527dca9d54d4cbcbdbb445a2d5.m4a");
URLConnection urlConnection = (HttpURLConnection)url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
FileOutputStream fos = new FileOutputStream("a.m4a");
byte[] buffer = new byte[1024];
int len;
while((len = inputStream.read(buffer))!= -1){
fos.write(buffer,0, len);
}
fos.close();
inputStream.close();
((HttpURLConnection) urlConnection).disconnect();
}
}
即时传输(创建对话)
一.发送端对应的类
1.创建发送端的socket
2.创建输入流(调用输入),再将其包装成Reader
3.将其线程化(实现Runnable)
4.运行此类时:
将流转换为字符串,再将字符串转化为字节
将字节打包成数据报
通过socket把数据报传出
添加结束判断,如果输入流转化为字符串后有"bye"那么跳出循环(结束线程)
public class TalkSend implements Runnable{
DatagramSocket socket = null;
BufferedReader reader= null;
private int fromPort;
private String toIP;
private int toPort;
public TalkSend(int fromPort,String toIP,int toPort){
this.fromPort = fromPort;
this.toIP = toIP;
this.toPort = toPort;
try{
socket = new DatagramSocket(fromPort);
reader = new BufferedReader(new InputStreamReader(System.in));
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void run(){
while(true){
try{
String data = reader.readLine();
byte[] dataBytes = data.getBytes();
DatagramPacket packet = new DatagramPacket(dataBytes,0,dataBytes.length,
new InetSocketAddress(this.toIP,this.toPort));
socket.send(packet);
if(data.equals("bye")){
break;
}
}catch (Exception e){
e.printStackTrace();
}
}
socket.close();
}
}
二.接收端对应的类
1.创建接收端的socket
2.将其线程化(实现Runnable)
3.运行此类时:
创建数据报来接收传过来的数据报
将数据报转化为字节数组,再转化为字符串
做结束进程判断(若接收到的字符串有bye,那么结束进程)
public class TalkReceive implements Runnable{
DatagramSocket socket = null;
private int port;
private String msgfrom;
public TalkReceive(int port,String msgfrom){
this.port = port;
this.msgfrom = msgfrom;
try{
//DatagramSocket socket = new DatagramSocket(port);
this.socket = new DatagramSocket(port);
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void run() {
while(true){
try {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
socket.receive(packet);
byte[] data = packet.getData();
String receiveData = new String(data, 0, packet.getLength());
//注意接收数据包中内容时开始为0,终止用packet.getLength(),不能用data.lenth,否则乱码
System.out.println(msgfrom+":"+receiveData);
System.out.println("qwerasd");
//如果传来的数据是bye则断开接收
if(receiveData.trim().equals("bye")){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三.应用接收和发送类实现互交
1.创建两个实现对象类
2.两个都调用接收线程和发送线程
public class TalkTeather {
public static void main(String[] args) {
new Thread(new TalkSend(5555,"localhost",8999)).start();
new Thread(new TalkReceive(9999,"student")).start();
}
}
public class TalkStudent {
public static void main(String[] args) {
new Thread(new TalkSend(7777,"localhost",9999)).start();
new Thread(new TalkReceive(8999,"teacher")).start();
}
}