JAVA网络-socket

两种常见的网络协议的支持:
TCP: TCP是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称TCP / IP。
UDP:UDP是用户数据报协议的缩写,一个无连接的协议。提供了应用程序之间要发送的数据的数据包。

三次握手

在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接,如图1所示。
(1)第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。
(2)第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。
(3)第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。

客户端向服务器发送一个SYN J
服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1
客户端再向服务器发一个确认ACK K+1
这里写图片描述
socket中TCP的四次握手释放连接详解
1 某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
2另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;
3 一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;
4接收到这个FIN的源发送端TCP对它进行确认。
这样每个方向上都有一个FIN和ACK。
这里写图片描述

Socket类

java.net.Socket类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个Socket对象通过实例化 ,而服务器获得一个Socket对象则通过ServerSocket的accept()方法的返回值。

构造方法

public Socket(String host, int port)创建一个流套接字并将其连接到指定主机上的指定端口号。
public Socket(InetAddress host, int port) throws IOExceptio 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
public Socket(String host, int port, InetAddress localAddress, int localPort) 创建一个套接字并将其连接到指定远程主机上的指定远程端口。
public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) 创建一个套接字并将其连接到指定远程地址上的指定远程端口。
public Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字

常用方法

public void connect(SocketAddress host, int timeout)将此套接字连接到服务器,并指定一个超时值。
void bind(SocketAddress bindpoint) 将套接字绑定到本地地址。
public InputStream getInputStream() 返回此套接字的输入流。
public OutputStream getOutputStream() 返回此套接字的输出流。
public void close() 关闭此套接字。
public InetAddress getInetAddress() 返回套接字连接的地址。
public int getPort() 返回此套接字连接到的远程端口。
public int getLocalPort() 返回此套接字绑定到的本地端口。
public SocketAddress getRemoteSocketAddress() 返回此套接字连接的端点的地址,如果未连接则返回 null。

ServerSocket 类

服务器应用程序通过使用java.net.ServerSocket类以获取一个端口,并且侦听客户端请求。

构造方法

public ServerSocket(int port) 创建绑定到特定端口的服务器套接字。
public ServerSocket(int port, int backlog) 利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
public ServerSocket(int port, int backlog, InetAddress address) 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
public ServerSocket() 创建非绑定服务器套接字。

创建非绑定服务器套接字。 如果ServerSocket构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。

常用方法

public Socket accept() 侦听并接受到此套接字的连接。
public void bind(SocketAddress host, int backlog) 将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
public int getLocalPort() 返回此套接字在其上侦听的端口。
public void setSoTimeout(int timeout) 通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。

socket编程

客户端程序创建一个套接字,并尝试连接服务器的套接字(ServerSocket)。
当连接建立时,服务器会创建一个Socket对象( accept返回值)。客户端和服务器现在可以通过对Socket对象的写入和读取来进行进行通信。

步骤:
1服务器实例化一个ServerSocket对象,表示通过服务器上的端口通信。()
2服务器调用ServerSocket类 的accept()方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
3服务器正在等待时,一个客户端实例化一个Socket对象,指定服务器名称和端口号来请求连接。
4Socket类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个Socket对象能够与服务器进行通信。
5在服务器端,accept()方法返回服务器上一个新的socket引用,该socket连接到客户端的socket。
6连接建立后,通过使用I/O流在进行通信。每一个socket都有一个输出流和一个输入流。客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。

TCP是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送。
当Socket构造方法返回,并没有简单的实例化了一个Socket对象,它实际上会尝试连接到指定的服务器和端口。

参考代码

客户端

public class GreetingClient
{
public static void main(String [] args)
{
String serverName = args[0];
int port = Integer.parseInt(args[1]);
try
{
System.out.println(“Connecting to ” + serverName
+ ” on port ” + port);
//创建一个Socket对象,指定IP地址和端口号(服务器端的)
//Socket类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个Socket对象能够与服务器进行通信
Socket client = new Socket(serverName, port);
System.out.println(“Just connected to ”
+ client.getRemoteSocketAddress());
//获取输出流
OutputStream outToServer = client.getOutputStream();
DataOutputStream out =
new DataOutputStream(outToServer);

        //往输出流写
        out.writeUTF("Hello from "
                + client.getLocalSocketAddress());
        //获取输入流
        InputStream inFromServer = client.getInputStream();
        DataInputStream in =
                new DataInputStream(inFromServer);
        System.out.println("Server says " + in.readUTF());
        //socket关闭
        client.close();
    }catch(IOException e)
    {
        e.printStackTrace();
    }
}

}

服务端

public class GreetingServer extends Thread
{
    private ServerSocket serverSocket;

    public GreetingServer(int port) throws IOException
    {
        //创建服务器套接字serverSocket,(指定了port绑定到特定端口的服务器套接字)
        //实例化一个ServerSocket对象,表示通过服务器上的端口通信
        serverSocket = new ServerSocket(port);
        //设置
        serverSocket.setSoTimeout(10000);
    }

    public void run()
    {
        while(true)
        {
            try
            {
                System.out.println("Waiting for client on port " +
                        serverSocket.getLocalPort() + "...");
                //侦听并接受到此套接字的连接。
                //accept()这个方法是一个阻塞的方法,如果客户端没有发送请求,那么代码运行到这里被阻塞,停在这里不再向下运行了,一直等待accept()函数的返回,这时候突然客户端发送一个请求,那个这个方法就会返回Socket对象,
                //accept()方法返回服务器上一个新的socket引用,该socket连接到客户端的socket。
                Socket server = serverSocket.accept();
                System.out.println("Just connected to "
                        + server.getRemoteSocketAddress());
                //获取输入流
                DataInputStream in =
                        new DataInputStream(server.getInputStream());
                System.out.println(in.readUTF());
                //获取输出流
                DataOutputStream out =
                        new DataOutputStream(server.getOutputStream());
                out.writeUTF("Thank you for connecting to "
                        + server.getLocalSocketAddress() + "\nGoodbye!");
                server.close();
            }catch(SocketTimeoutException s)
            {
                System.out.println("Socket timed out!");
                break;
            }catch(IOException e)
            {
                e.printStackTrace();
                break;
            }
        }
    }
    public static void main(String [] args)
    {
        int port = Integer.parseInt(args[0]);
        try
        {
            Thread t = new GreetingServer(port);
            t.start();
        }catch(IOException e)
        {
            e.printStackTrace();
        }
    }
}

编译以上 java 代码,并执行以下命令来启动服务,使用端口号为 6066:
$ java GreetingServer 6066
Waiting for client on port 6066…

像下面一样开启客户端:
$ java GreetingClient localhost 6066
Connecting to localhost on port 6066
Just connected to localhost/127.0.0.1:6066
Server says Thank you for connecting to /127.0.0.1:6066
Goodbye!

bind和connect

connect
当Socket构造方法返回,并没有简单的实例化了一个Socket对象,它实际上会尝试连接到指定的服务器和端口。
你可以创建Socket时指定服务器和端口。
也可以创建Socket后调用connect指定服务器和端口。
connect(SocketAddress host, int timeout)
将此套接字连接到服务器,并指定一个超时值。

bind

tcp时在服务端
ServerSocket() 创建并绑定到指定端口的服务器套接字(不带参数是创建非绑定服务器套接字)
你也可以通过bing来绑定服务器套接字

采用TCP通信时,客户端不需要bind()他自己的IP和端口号,而服务器必须要bind()自己本机的IP和端口号;
若采用UDP通信时(这里是有客户端和服务器之分才这么说的,若是指定特定端口的UDP对等通信则不一样了),客户端也可以不需要bind()他自己的IP和端口号,而服务器需要bind自己IP地址和端口号;

无连接的socket的客户端和服务端以及面向连接socket的服务端通过调用bind函数来配置本地信息。
Bind()函数在成功被调用时返回0;出现错误时返回”-1”并将errno置为相应的错误号。需要注意的是,在调用bind函数时一般不要将端口号置为小于1024的值,因为1到1024是保留端口号,你可以选择大于1024中的任何一个没有被占用的端口号。

有连接的socket客户端通过调用Connect函数在socket数据结构中保存本地和远端信息,无须调用bind(),因为这种情况下只需知道目的机器的IP地址,而客户通过哪个端口与服务器建立连接并不需要关心,socket执行体为你的程序自动选择一个未被占用的端口,并通知你的程序数据什么时候打开端口。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值