java中的套接字与网络编程

发布于:2024-05-01 ⋅ 阅读:(22) ⋅ 点赞:(0)

目录

Socket套接字

流套接字与数据报套接字

UDP数据报套接字编程


Socket套接字

⽹络编程,指⽹络上的主机,通过不同的进程,以编程的⽅式实现⽹络通信或称为⽹络数据传 输)。Socket套接字是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程。

操作系统提供的socket api 不止有一套,而是有好几套。

Socket套接字主要针对传输层协议分为如下三类:

1)流套接字:使用传输层TCP协议。

2)数据报套接字:使用传输层UDP协议。

3)Unix域套接字:不能跨主机通信,只是本地主机上的进程和进程之间的通信方式(现在使用的很少了,我们这里不做讨论)。

流套接字与数据报套接字

  TCP和UDP都是传输层协议,都是给应用层提供服务的。但是由于这两个协议的特点,差异非常大,印次我们需要搞两套api来分别表示。

特点:

TCP:有连接,可靠传输,面向字节流,全双工。

UDP:无连接,不可靠传输,面向数据报,全双工。

有连接 VS 无连接

计算机中的连接(Connection) 是一个”抽象的概念“,计算机的连接认为是要建立连接的双方,各自保存对方的信息。此时,就认为是建立了一个”抽象的连接“。有连接就是通信双方保存对方的信息,无连接就是通信双方不需要保存对方的信息。有连接就好比打电话,只有对方接听,两方才能通信。无连接就好比发微信,不需要”先接通“,直接就可以发送。

可靠传输 VS 不可靠传输

可靠传输即将要传输的数据尽可能地传输给对方。TCP内部提供了一系列的机制,来实现可靠传输。(即使”尽可能“也无法保证100%传输,因为网络环境过于复杂,丢包是不能完全避免的)。

UDP则是不可靠传输,传输数据的时候,不关心对方是否收到,发了就完事了。而UDP的优势是传输效率较快

面向字节流 VS 面向数据报

  字节流数据的特征是在IO流没有关闭的时候,是无边界的数据,可以多次发送,也可以分开多次接收,就像水流一样,读写操作非常灵活。而面向数据报,传输的数据是一块一块的,传输数据的基本单位是一个个的UDP数据报,一次读写只能读写一个完整的UDP数据报,不能搞半个,也不能一个半。

全双工 VS 半双工

全双工:一条链路,能够进行双向通信。

半双工:一条链路,只能进行单向通信。

TCP,UDP都是全双工。

因为网线里面都是电信号,从这边进那边出,还是从那边近这边出,都是可以的。

UDP数据报套接字编程

系统中的socket,可以理解为是一种文件,socket文件,就可以视为是“网卡”这种硬件设备的抽象表现形式针对socket文件的读写操作,就相当于针对网卡这个硬件设备进行读写。比如,你想操控空调,直接去按空调不方便,就可以拿遥控器来操作。具有“遥控器属性”这样的概念,计算机中起了个专门的名字“句柄(handle)”.

java中提供了很多的socket api ,重点是两个类:

1)DatagramSocket

DatagramSocket可以视为是“操作网卡”的遥控器,针对这个对象进行读写操作,就是针对网卡进行读写操作。其中比较关键的方法:

注:socket也是一种文件,用完也要关闭,否则会占着文件描述符表的一个表项。

2)DatagramPacket

针对UDP数据报的一个抽象表示,一个DatagranPacket对象,就相当于一个UDP数据报。一次发送/一次接收,就是传输了一个DatagramPacket对象。

下面我们通过java代码实现客户端与服务端的通信:

服务端代码:

package Web;

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

public class UdpEchoServer {
    private DatagramSocket socket = null;

    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动");
        while (true){
            //1.读取请求并解析
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            //为了方便在java中处理,可以把上述数据报中的二进制数据构造成String
            String request = new String(requestPacket.getData(), 0,requestPacket.getLength());
            //2.根据请求计算响应
            String response = process(request);
            //3.把响应写回到客户端
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),0,response.getBytes().length,
                  requestPacket.getSocketAddress() );
            socket.send(responsePacket);
            //打印ip地址和端口号
            System.out.printf("[%s : %d] req = %s , resp = %s\n",requestPacket.getAddress(), requestPacket.getPort(),
                    request,response);
            
        }
    }

    private String process(String request) {
        //由于回显,请求和响应是一样的
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer server = new UdpEchoServer(9090);
        server.start();

    }
}

注:Echo称为回显,正常的服务器,给它发送不同的请求,会返回不同的响应。回显的意思是请求发了啥,响应就是啥,这个过程中,没有计算,也没有业务逻辑。 此处使用回显,是为了帮大家单纯的去认识socket api的用法。

用户端代码:

package Web;

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

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp;
    private  int serverPort;

    public UdpEchoClient(String serverIp,int serverPort) throws SocketException {
        socket = new DatagramSocket();
        this.serverIp = serverIp;
        this.serverPort = serverPort;
    }

    public void start() throws IOException {
        System.out.println("客户端启动");
        Scanner sc = new Scanner(System.in);
        while (true){
            System.out.print("请输入要发送的请求");
            //1.从控制台读取用户输入
            String request = sc.next();
            //2.构造请求并发送
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),0,request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            //3.读取响应数据
             DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
             socket.receive(responsePacket);
             //4.显示响应到控制台上
            String response = new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);
        }
    }
    public static void main(String[] args) throws IOException {
         UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);
         client.start();
    }
}

以上,关于网络编程,希望对你有所帮助。


网站公告

今日签到

点亮在社区的每一天
去签到