网络编程_简介+socket实现

1:网络编程简介

1:网络编程是什么?

网络编程可以让程序与网络上的其他设备中的程序进行数据交互。

2:网络通信基本模式(C/S、B/S)

常见的通信模式有如下2种形式:Client-Server(CS) 、 Browser/Server(BS)

C/S架构 QQ 微信 性能高,用户体验好 成本高,升级不方便

s=Server服务器

c=Client客户端

B/S架构 开发维护成本低,服务升级方便

S=Server服务器

B=Broser浏览器

2:网络通信三要素

IP地址:设备在网络中的地址,是唯一的标识。(127.0.0.1)

端口:应用程序在设备中唯一的标识。(8080)

协议: 数据在网络中传输的规则,常见的协议有UDP协议和TCP协议。(http,tcp)

1:IP地址(网络中每台计算机的一个标识号)

  • IP(Internet Protocol):全称”互联网协议地址”,是分配给上网设备的唯一标志。

  • 常见的IP分类为:IPv4和IPv6

 

 

IP地址形式

  • 公网地址、和私有地址(局域网使用)。

  • 192.168. 开头的就是常见的局域网地址,范围即为192.168.0.0--192.168.255.255,专门为组织机构内部使用。

IP地址分类:

IP地址分为5类,A类保留给政府机构,B类分配给中等规模的公司,C类分配给任何需要的人,D类用于组播,E类用于实验,各类可容纳的地址数据不同。

NO.地址分类地址范围
1A类地址1.0.0.1——126.255.255.254
2B类地址128.0.0.1——191.255.255.254
3C类地址192.0.0.1——223.255.255.254
4D类地址224.0.0.1——239.255.255.254
5E类地址240.0.0.1——255.255.255.254

如何查看本机IP地址,如何看是否与对方互通 ipcofig ping 192.168.10.23

特殊IP地址:

本机IP: 127.0.0.1或者localhost:称为回送地址也可称本地回环地址,只会寻找当前所在本机。

2:端口号(唯一标识正在计算机设备上运行的进程(程序))

  • 端口号:标识正在计算机设备上运行的进程(程序),被规定为一个 16 位的二进制,范围是 0~65535。

  • 端口类型 周知端口:0~1023,被预先定义的知名应用占用(如:HTTP占用 80,FTP占用21)

  • 注册端口:1024~49151,分配给用户进程或某些应用程序。(如:Tomcat占 用8080,MySQL占用3306)

  • 动态端口:49152到65535,之所以称为动态端口,是因为它 一般不固定分配某种进程,而是动态分配。

    注意:我们自己开发的程序选择注册端口,且一个设备中不能出现两个程序的端口号一样,否则出错。

端口号的作用是什么? 唯一标识正在计算机设备上运行的进程(程序)

端口与协议有关:TCP和UDP的端口互不相干

3:协议TCP/IP协议

连接和通信数据的规则被称为网络通信协议

1:传输层的2个常见协议
  • TCP(Transmission Control Protocol) :传输控制协议

  • UDP(User Datagram Protocol):用户数据报协议

2:TCP协议特点

TCP/IP协议(定义了电子设备(比如计算机)如何连入因特网,以及数据如何在它们之间传输的标准):

Internet上不同系统之间互联的一组协议

为分散和不同类型的硬件提供通用的编程接口。

TCP/IP协议使Internet尽可能成为一个分散、无序的网络。

TCP是基于(面向)连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接。

  • 使用TCP协议,必须双方先建立连接,它是一种面向连接的可靠通信协议。

  • 传输前,采用“三次握手”方式建立连接,所以是可靠的 。

  • 在连接中可进行大数据量的传输 。

  • 连接、发送数据都需要确认,且传输完毕后,还需释放已建立的连接,通信效率较低。

3:TCP三次握手确立连接

 

 

4:TCP四次挥手断开连接

 

4:UDP协议

1:UDP协议:
  • UDP是一种无连接、不可靠传输的协议。

  • 将数据源IP、目的地IP和端口封装成数据包,不需要建立连接

  • 每个数据包的大小限制在64KB内

  • 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的

  • 可以广播发送 ,发送数据结束时无需释放资源,开销小,速度快。

2:UDP协议的特点
  • 用户数据报协议(User Datagram Protocol)

  • UDP是面向无连接,不可靠传输的通信协议。

  • 速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据。

3:UDP通信实现:发送消息、接收消息

5:网络通信的实现

思考网络编程要解决的问题:

1.如何建立两个节点(电脑)之间的网络连接?

2.如何向另外一个节点(电脑)发送信息?

3.如何从外部节点(电脑)接收一个请求并给预响应?

4.如何利用网络协议(TCP,UDP)?

1:socket编程简介

套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。

当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。

java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。

当然,这里的ServerSocket只是socket通信中的一种,实际上,socket通信有三种模式来让我们实现:

1.流式套接字

提供了一个面向连接,可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接收,其实他对应使用的是TCP协议

2.数据报式套接字

面向无连接,数据报以独立包形式发送,不提供无差错保证,数据可能丢失或重复,并且接收顺序无序,其实他对应使用的是UDP协议

3.原始式套接字

该接口允许对较低层次协议,如IP直接访问。可以接收本机网卡上的数据帧或数据包,对监听网络流量和分析很有用

2:TCP协议通信
1:普通实现代码

客户端代码:

package tcp;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {

    public static void main(String[] args) throws IOException {

//        创建一个socket管道 与 服务器连接
        Socket socket = new Socket("127.0.0.1", 7777);
//        获取到字节输出流
        OutputStream outputStream = socket.getOutputStream();
//        创建一个打印流,进行输出内容
        PrintStream printStream = new PrintStream(outputStream);
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.println("请说");
            String s = scanner.nextLine();
            printStream.println(s);
            printStream.flush();
        }

    }
}

服务端代码:

package tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

    public static void main(String[] args) throws IOException {
//        创建一个serversocket
        ServerSocket serverSocket = new ServerSocket(7777);
        Socket socket = serverSocket.accept();
//        将通道交给一个新的线程去处理
//        获取字节输入流
        InputStream inputStream = socket.getInputStream();
//        将字节流转化为字符流
        InputStreamReader reader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(reader);
        String line = null ;
        while((line=bufferedReader.readLine())!=null){
            System.out.println(line);
        }


    }
}
2:多线程

Client

package tcp2;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {

    public static void main(String[] args) throws IOException {

//        创建一个socket管道 与 服务器连接
        Socket socket = new Socket("127.0.0.1", 7777);
//        获取到字节输出流
        OutputStream outputStream = socket.getOutputStream();
//        创建一个打印流,进行输出内容
        PrintStream printStream = new PrintStream(outputStream);
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.println("请说");
            String s = scanner.nextLine();
            printStream.println(s);
            printStream.flush();
        }

    }
}

Server:

package tcp2;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

    public static void main(String[] args) throws IOException {
//        创建一个serversocket
        ServerSocket serverSocket = new ServerSocket(7777);
//        不断的去接收请求
        while(true) {
            Socket socket = serverSocket.accept();
            //        将连接通道交给一个新的线程来处理
            new ServerNewThread(socket).start();
        }


    }
}

ServerNewThread:

package tcp2;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;

//创建一个线程类
public class ServerNewThread extends Thread{

    private Socket socket  ;
    public ServerNewThread(Socket socket){
        this.socket = socket ;
    }
    @Override
    public void run() {

//        获取字节输入流
        InputStream inputStream = null ;
        try {
            inputStream = socket.getInputStream();
            //        将字节流转化为字符流
            InputStreamReader reader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(reader);
            String line = null ;
            while((line=bufferedReader.readLine())!=null){
                System.out.println(line);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
3:线程池

Client:

package tcp3;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {

    public static void main(String[] args) throws IOException {

//        创建一个socket管道 与 服务器连接
        Socket socket = new Socket("127.0.0.1", 7777);
//        获取到字节输出流
        OutputStream outputStream = socket.getOutputStream();
//        创建一个打印流,进行输出内容
        PrintStream printStream = new PrintStream(outputStream);
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.println("请说");
            String s = scanner.nextLine();
            printStream.println(s);
            printStream.flush();
        }

    }
}

Server

package tcp3;


import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Server {
// 创建一个连接池对象
    /*int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler*/
    static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            5,
            20,
            5,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(2),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy()
);
    public static void main(String[] args) throws IOException {
//        创建一个serversocket
        ServerSocket serverSocket = new ServerSocket(7777);
//        不断的去接收请求
        while(true) {
            Socket socket = serverSocket.accept();
            System.out.println(socket.getRemoteSocketAddress()+"它来了");
            //        将连接通道交给一个新的线程来处理
            Runnable runnable = new ServerNewThread2(socket);
            threadPoolExecutor.execute(runnable);
        }


    }
}

Thread

package tcp3;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;

//创建一个线程类
public class ServerNewThread2 extends Thread{

    private Socket socket  ;
    public ServerNewThread2(Socket socket){
        this.socket = socket ;
    }
    @Override
    public void run() {

//        获取字节输入流
        InputStream inputStream = null ;
        try {
            inputStream = socket.getInputStream();
            //        将字节流转化为字符流
            InputStreamReader reader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(reader);
            String line = null ;
            while((line=bufferedReader.readLine())!=null){
                System.out.println(line);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
4:客户端和服务端交互,多线程接收和发送同时进行(max)

Server:

package tcp_practise3;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class Server {
    private PrintWriter writer;
    private BufferedReader reader;
    private ServerSocket server;
    private Socket socket;
    private Scanner scanner;
    public void getServer() {
        try {
            //设置端口号
            server = new ServerSocket(6666);
            System.out.print("服务器端已经创建成功\n");
            while (true) {
                System.out.print("等待客户端的连接......\n");
                //接收客户端连接
                socket = server.accept();
                //进行IO的输入和输出
                reader = new BufferedReader(new InputStreamReader(socket
                        .getInputStream()));
                //autoFlush是允许加权
                writer = new PrintWriter(socket.getOutputStream(), true);
                //调用函数
                getClientInfo();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //接收数据
    private void getClientInfo() {
        try {
            while (true) {
                //读取一行数据
                String line = reader.readLine();
                //判断是否为空
                if (line != null)
                    // 获得客户端信息
                    System.out.print("接收到客户端发送的信息:" + line + "\n");
                System.out.print("请回复:");
            }
        } catch (Exception e) {
            System.out.print("客户端已退出。\n");
        } finally {
            try {
                if (reader != null) {
                    reader.close();// 关闭流
                }
                if (socket != null) {
                    socket.close(); // 关闭套接字
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //发送数据
    private void sendInfoToClient(){
        while(true){
            scanner=new Scanner(System.in);
            System.out.println("请输入要发送的消息:");
            String msg=scanner.nextLine();
            //判断是否为quit退出
            if(msg.equals("quit")){
                break;
            }
            writer.println(msg);
        }
    }
    //多线程的方式进行数据的交互
    public static void main(String[] args) {
        //创建server对象
        Server server = new Server();
        //此线程用于监听接收消息
        new Thread(new Runnable() {
            @Override
            public void run() {
                server.getServer();
            }
        }).start();
        //此线程用发送消息给客户端
        new Thread(new Runnable() {
            @Override
            public void run() {
                server.sendInfoToClient();
            }
        }).start();
    }
}

Client:

package tcp_practise3;

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    private PrintWriter writer;
    private BufferedReader reader;
    private Socket socket;
    private Scanner scanner;

    private void connect() {
        System.out.print("尝试连接......\n");
        try {
//            连接Socket地址和端口号
            socket = new Socket("127.0.0.1", 6666);
            while (true) {
                //IO流的输入和输出
                writer = new PrintWriter(socket.getOutputStream(), true);
                reader = new BufferedReader(new InputStreamReader(socket
                        .getInputStream()));
                System.out.print("完成连接。\n");
                getClientInfo();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 对服务器的发送消息进行监听
     */
    private void getClientInfo() {
        try {
            while (true) {
                if (reader != null) {
                    //读取一行数据
                    String line = reader.readLine();
                    if (line != null)
                        System.out.print("接收到服务器端发送的信息:" + line + "\n");
                    System.out.print("请回复:");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 向服务器发送消息方法
     */
    private void sendInfoToServer(){
        while(true){
            scanner=new Scanner(System.in);
            System.out.println("请输入要发送的消息:");
            String msg=scanner.nextLine();
            //判断是否离开
            if(msg.equals("quit")){
                break;
            }
            writer.println(msg);
        }
    }
    //多线程的方式进行数据交互
    public static void main(String[] args) {
        Client clien = new Client();
        //此线程用于监听接收消息
        new Thread(new Runnable() {
            @Override
            public void run() {
                clien.connect();
            }
        }).start();
        //此线程用发送消息给服务器
        new Thread(new Runnable() {
            @Override
            public void run() {
                clien.sendInfoToServer();
            }
        }).start();
    }
}
3:UDP协议通信

UDP是一个面向无连接,不可靠的传输层协议.

需要用到两个类:DatagramSocket,DatagramPacket

DatagramSocket类的作用:发送和接收数据包的套接字,不维护连接状态,不产生输入输出流

DatagramPacket类:数据包,封装了数据,数据长度

DatagramPacket构造方法:

构造方法说明
DatagramPacket(byte [] buf,int length,InetAddress address,int port)Buf是数据的字节数组,length是字节数组的长度,address是目标主机的IP地址,port是目标主机的端口 该构造用来构造对象,将长度为length的包发送到指定主机上的指定端口号

DatagramSocket的构造方法:

构造方法说明
DatagramSocket()创建DatagramSocket对象,并将其与本地主机上任何可用的端口绑定
DatagramSocket(int port)创建一个DatagramSocket对象,并将其与本地主机上的指定端口绑定

注意:在UDP通信中,通信的双方中,至少有一方需要指定端口号

DatagramSocket的常用方法:

常用方法说明
void send(DatagramPacket p)发送指定的数据报
void receive(DatagramPacket p)接收数据报.收到数据以后,存放在指定的DatagramPacket对象中
void close()关闭当前的DatagramSocket对象
1:服务端实现

UDP通信中并不需要明确的服务器概念,双方几乎是一样的操作,如下见服务器代码实现:

package cn.gl.no1;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class Client1 {

	public static void main(String[] args) {
		DatagramSocket socket = null;
		try {
			//参与通讯的两方,至少应该有一边指定端口号
			socket = new DatagramSocket();
			
			String msg = "我要发送的短信内容";
			//dp对象,是用来把要发送的信息打成一个数据包
			//数据长度不能超过64K
			//构造中可以传递四个参数:
			//第一个参数,表示要发送的内容,需要转换成一个byte数组
			byte [] b = msg.getBytes();
			//第二个参数,表示发送内容的字节数
			int len = b.length;
			//第三个参数,表示IP地址封装的一个对象,类型是InetAddress,是接收方的地址
			InetAddress ia = InetAddress.getByName("localhost");
			//第四个参数,表示对方的端口号
			int port = 8888;
			DatagramPacket dp = new DatagramPacket(b, len, ia, port);
			
			socket.send(dp);
			
			byte [] bs = new byte[1024];
			int length = bs.length;
			DatagramPacket dpReceive = new DatagramPacket(bs, length);
			socket.receive(dpReceive);
			String reply = new String(bs,0,dpReceive.getLength());
			System.out.println("我是client1,收到信息:"+reply);
			
			
			socket.close();
		} catch (SocketException e) {
			e.printStackTrace();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
2:客户端实现
package cn.gl.no1;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;

public class Client2 {

	public static void main(String[] args) {
		DatagramSocket socket = null;
		try {
			socket = new DatagramSocket(8888);
			
			//这里为了接收数据,也需要一个空的数据包
			//两个参数:
			//第一个参数,表示一个空的byte数组,用来接收信息内容
			byte [] b = new byte[1024];
			//第二个参数,表示数组长度
			int len = b.length;
			DatagramPacket dp = new DatagramPacket(b, len);
			//接收信息
			socket.receive(dp);
			String msg = new String(b,0,dp.getLength());
			System.out.println("我是Client2,接收到信息:"+msg);
			
			String reply = "我很好,收到你的信息,很高兴,谢谢";
			byte [] bs = reply.getBytes();
			int length = bs.length;
			InetAddress ia = dp.getAddress();
			/*InetSocketAddress isa = (InetSocketAddress) dp.getSocketAddress();
			System.out.println("isa.getHostName():"+isa.getHostName());
			System.out.println("isa.getHostString():"+isa.getHostString());
			System.out.println("isa.getPort():"+isa.getPort());*/
			int port = dp.getPort();
			DatagramPacket dpReply = new DatagramPacket(bs, length, ia, port);		
			socket.send(dpReply);

			socket.close();
		} catch (SocketException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

3:总结

1:网络通信三要素:ip , 端口号,协议

2:tcp的三挥四握

3:关于socket编程的客服端和服务端叫交互信息:tcp的多线程,线程池。udp的客户端服务端实现方法

4、建议采纳

如有建议或者错误请私信我进行修改,感谢!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值