Socket网络编程详解

一、Socket简介

1.1、socket通信基本原理

首先socket 通信是基于TCP/IP 网络层上的一种传送方式。在七个层级关系中,我们将的socket属于传输层

什么是Socket:socket是基于应用服务与TCP/IP通信之间的一个抽象,他将TCP/IP协议里面复杂的通信逻辑进行分装,对用户来说,只要通过一组简单的API就可以实现网络的连接。

原理图:

大致原理:

服务端初始化ServerSocket,然后对指定的端口进行绑定,接着对端口及进行监听,通过调用accept方法阻塞,这时候,如果客户端有一个socket连接到服务端,那么服务端通过监听和accept方法可以与客户端进行连接

1.2、网络中进程之间如何通信?

(1)先了解本地进程间怎么通信

  • 消息传递(管道、FIFO、消息队列)

  • 同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)

  • 共享内存(匿名的和具名的)

  • 远程过程调用(Solaris门和Sun RPC)

(2)网络中进程之间如何通信?

Socket(open—write/read—close)

(3)网络中通信要解决的问题:唯一标识一个进程

在本地可以通过进程PID来唯一标识一个进程。网络中不行。TCP/IP协议族已经解决了这个问题,

网络层的“ip地址”可以唯一标识网络中的主机,

而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)

这样利用三元组(ip地址,协议,端口)就可以了

1.3、Socket通信总的步骤

①服务端:创建ServerSocket对象,绑定监听端口

②服务端:通过accept()方法监听客户端请求

③客户端:创建Socket对象,指明需要连接的服务器的地址和端口号

④客户端:连接建立后,通过输出流向服务器发送请求信息

⑤服务端:连接建立后,通过输入流读取客户端发送的请求信息

⑥服务端:通过输出流向客户端发送响应信息

⑦客户端:通过输入流获取服务器相应的信息

二、Socket类

2.1、使用Socket连接服务器的过程包含以下4个基本的步骤

什么是Socket:

套接字(Socket)是一个抽象层,应用程序可以通过它发送或接收数据;就像操作文件那样可以打开、读写和关闭。套接字允许应用程序将 I/O 应用于网络中,并与其他应用程序进行通信。

(1)创建Socket

Socket(String host, int port)throws UnknownHostException, IOException;
Socket(InetAddress address, int port)throws UnknownHostException, IOException;
Socket(InetAddress address, int port, InetAddress localAddress, int localPort)throws IOException;
//下边这个方法参数为:目标IP、目标端口、绑定本地IP、绑定本地端口
Socket(String host, int port, InetAddress localAddress, int localPort)throws IOException;

第一种方法用的最多。

InetAddress:是一个用于记录主机的类,其静态getHostByName(String msg)可以返回一个实例,其静态方法getLocalHost()也可以获得当前主机的IP地址,并返回一个实例;

注意

在Socket建立的时候,如果远程主机不可访问,会阻塞很长时间,所以要设立超时时间:

Socket socket = new Socket(...);
socket.setSoTimeout(10000); 
// 单位为毫秒


(2)打开连接到Socket的输入/输出流
(3)按照一定协议对Socket执行读写操作
(4)关闭Socket

2.2、Socket方法介绍

getInetAddress();      远程服务端的IP地址
getPort();          远程服务端的端口
getLocalAddress()      本地客户端的IP地址
getLocalPort()        本地客户端的端口
getInputStream();     返回与调用的套接字相关联的输入流
getOutStream();      返回与调用的套接字相关联的输出流
//最后两个方法很重要

2.3、Socket状态介绍

isClosed();            //连接是否已关闭,若关闭,返回true;否则返回false
isConnect();      //如果曾经连接过,返回true;否则返回false
isBound();            //如果Socket已经与本地一个端口绑定,返回true;否则返回false
isConnected();              //判断Socket的连接状态

 

三、ServerSocket类

作用:服务器端用来监听特定端口上客户端的连接,也可以发送信息

构造函数:

ServerSocket()throws IOException;
ServerSocket(int port)throws IOException;
ServerSocket(int port, int backlog)throws IOException;
ServerSocket(int port, int backlog, InetAddress bindAddr)throws IOException;

 port:服务端要监听的端口;

backlog:客户端连接请求的队列长度;

bindAddr:服务端绑定IP。

3.1、使用ServerSocket监听Socket包含4个基本的步骤

(1)创建ServerSocket
(2)监听客户端的连接(accept()方法)
(3)打开连接到ServerSocket的输入/输出流
(4)按照一定协议对ServerSocket执行读写操作

注意:Socket需要自己关闭,但是ServerSocket不需要自己关闭

 

四、实战

4.1、案例1

(1)客户端

class Client{
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",8080);
//        用一个子线程处理服务器端数据
        new Thread(new CilentThread(socket)).start();
//        从终端接收数据,发给客户端
        BufferedReader keyIn = new BufferedReader(new InputStreamReader(System.in));
        PrintStream ps = new PrintStream(socket.getOutputStream());
        String line = null;
        while ((line = keyIn.readLine()) != null){
            ps.println(line);
        }
    }
}
//创建一个客户端的子线程,接收客户端发送的数据
class CilentThread implements Runnable{
    private Socket socket;
    public CilentThread (Socket socket){
        this.socket = socket;
    }
    @Override
    public void run(){
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = null;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("网络出错,请检查");
            System.exit(-1);
        }finally {
                try {
                    if (br != null) {
                        br.close();
                    }
                    if (socket != null){
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }
}

(2)服务端

class Server{
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8080);
        Socket socket = ss.accept();
//        创建一个子线程,处理客户端输入数据
        new ServerThread(socket).start();
//        接收终端的输入(字符)
        BufferedReader keyIn = new BufferedReader(new InputStreamReader(System.in));
//        客户端的输出流
        PrintStream ps = new PrintStream(socket.getOutputStream());
//        读取终端的输入,并输出给客户端
        String line = null;
        while ((line = keyIn.readLine()) != null) {
            ps.println(line);
        }
    }
}
//创建一个子线程接收客户端的数据
class  ServerThread extends Thread{
    private Socket socket = null;
    public ServerThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = null;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("网络异常,请重新登陆");
//            断开子线程
            System.exit(-1);
        }finally {
            try {
                if (br != null){
                    br.close();
                }
                if (socket != null){
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

参考:

https://www.jianshu.com/p/cde27461c226

https://blog.csdn.net/qq_31918961/article/details/80546537

https://www.jianshu.com/p/908aa099fab4

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值