基于Socket的Java网络编程
1,什么是Socket
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
TCP通信同UDP通信一样,都能实现两台计算机之间的通信,通信的两端都需要创建socket对象。
区别在于,UDP中只有发送端和接收端,不区分客户端与服务器端,计算机之间可以任意地发送数据。
而TCP通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信,服务器端不可以主动连接客户端,并且服务器端程序需要事先启动,等待客户端的连接。
2,Socket通讯的过程
Server端Listen(监听)某个端口是否有连接请求,Client端向Server 端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。Server端和Client 端都可以通过Send,Write等方法与对方通信。
对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:
(1)创建Socket;
(2)打开连接到Socket的输入/出流;
(3)按照一定的协议对Socket进行读/写操作;
(4)关闭Socket.
在JDK中提供了两个类用于实现TCP程序,一个是ServerSocket类,用于表示服务器端,一个是Socket类,用于表示客户端。
通信时,首先创建代表服务器端的ServerSocket对象,该对象相当于开启一个服务,并等待客户端的连接,然后创建代表客户端的Socket对象向服务器端发出连接请求,服务器端响应请求,两者建立连接开始通信。
3、ServerSocket
该类的实例对象可以实现一个服务器端的程序
1)构造方法
- ServerSocket() 创建非绑定服务器套接字。
- ServerSocket(int port) 创建绑定到特定端口的服务器套接字。
- ServerSocket(int port, int backlog) 利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
- ServerSocket(int port, int backlog, InetAddress bindAddr) 使用指定的端口、侦听 backlog (最大的等待队列)和要绑定到的本地 IP 地址创建服务器。
2)方法
(1)绑定地址
- bind(SocketAddress endpoint) void 将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
- bind(SocketAddress endpoint, int backlog) void 将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
- isBound() boolean 返回套接字的绑定状态。
(2)获取地址
- getInetAddress() InetAddress 返回此服务器套接字的本地地址。
- getLocalPort() int 返回此套接字在其上侦听的端口。
- getLocalSocketAddress() SocketAddress 返回此套接字绑定的端点的地址,如果尚未绑定则返回 null。
(3)设置缓冲区
- setReceiveBufferSize(int size) void 将此 Socket 的 SO_RCVBUF 选项设置为指定的值。
- setSendBufferSize(int size) void 将此 Socket 的 SO_SNDBUF 选项设置为指定的值。
(4)重用端口
- setReuseAddress(boolean on) void 启用/禁用 SO_REUSEADDR 套接字选项。
- getReuseAddress() boolean 测试是否启用 SO_REUSEADDR。
(5)接受连接
- accept() Socket 侦听并接受到此套接字的连接。
(6)关闭
- close() void 关闭此套接字。
- isClosed() boolean 返回套接字的关闭状态。
ServerSocket对象负责监听某台计算机的某个端口号,在创建ServerSocket对象后,需要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法之后,服务器端程序会发生阻塞,直到客户端发出连接请求,accept()方法才会返回一个Scoket对象用于和客户端实现通信,程序才能继续向下执行。
4、Socket
JDK提供了一个Socket类,用于实现TCP客户端程序
(1)构造方法
- Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字
- Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
- Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 创建一个套接字并将其连接到指定远程地址上的指定远程端口。
- Socket(Proxy proxy) 创建一个未连接的套接字并指定代理类型(如果有),该代理不管其他设置如何都应被使用。
- Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。
- Socket(String host, int port, InetAddress localAddr, int localPort) 创建一个套接字并将其连接到指定远程主机上的指定远程端口。
(2)成员方法
1)关联地址
- bind(SocketAddress bindpoint) void 将套接字绑定到本地地址。
- connect(SocketAddress endpoint) void 将此套接字连接到服务器。
- connect(SocketAddress endpoint, int timeout) void 将此套接字连接到服务器,并指定一个超时值。
- isBound() boolean 返回套接字的绑定状态。
- isConnected() boolean 返回套接字的连接状态。
2)获取IP地址
- getInetAddress() InetAddress 返回套接字连接的地址。
- getLocalAddress() InetAddress 获取套接字绑定的本地地址。
- getPort() int 返回此套接字连接到的远程端口。
- getLocalPort() int 返回此套接字绑定到的本地端口。
- getLocalSocketAddress() SocketAddress 返回此套接字绑定的端点的地址,如果尚未绑定则返回 null。
- getRemoteSocketAddress() SocketAddress 返回此套接字连接的端点的地址,如果未连接则返回 null。
3)获取数据
- getInputStream() InputStream 返回此套接字的输入流。
- getOutputStream() OutputStream 返回此套接字的输出流。
- getChannel() SocketChannel 返回与此数据报套接字关联的唯一 SocketChannel 对象(如果有)。
4)设置缓冲区
- setReceiveBufferSize(int size) void 将此 Socket 的 SO_RCVBUF 选项设置为指定的值。
- setSendBufferSize(int size) void 将此 Socket 的 SO_SNDBUF 选项设置为指定的值。
5)重用端口
- setReuseAddress(boolean on) void 启用/禁用 SO_REUSEADDR 套接字选项。
- getReuseAddress() boolean 测试是否启用 SO_REUSEADDR。
6)关闭
- close() void 关闭此套接字。
- isClosed() boolean 返回套接字的关闭状态。
5、简单的TCP网络程序
服务器端和客户端的数据传输:
要实现TCP通信需要创建一个服务器端程序和一个客户端程序,为了保证数据传输的安全性,首先需要实现服务器端程序
1) 服务端
package com.sxb.socket.common.server;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @Description socket服务端基础类:
* 服务端监听一个端口,等待连接的到来,服务端只能被动的接收客户端的请求,不能发送响应
* @Author ShiXinbing
* @Date 2018/7/25 0025 15:21
* @Version 1.0
**/
public class SocketServer {
public static void main(String[] args) throws IOException {
// 1 监听指定的端口号
int port = 55533;
// 2 创建ServerSocket对象
ServerSocket server = new ServerSocket(port);
// 3 开启server,将一直等待client的请求连接的到来
System.out.println("server将一直等待连接的到来。。。。。");
Socket socket = server.accept();
// 4 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
StringBuilder sb = new StringBuilder();
while ((len = inputStream.read(bytes)) != -1) {
//注意指定编码格式,发送方和接收方一定要统一,建议使用UTF-8
sb.append(new String(bytes, 0, len, "UTF-8"));
}
System.out.println("get message from client: " + sb);
// 关闭资源
inputStream.close();
socket.close();
server.close();
}
}
2)客户端
package com.sxb.socket.common.client;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
/**
* @Description 客户端通过ip和端口,连接到指定的server,然后通过Socket获得输出流,并向其输出内容,
* 服务器会获得消息。客户端只能发送请求,不能接收响应
* @Author ShiXinbing
* @Date 2018/7/25 0025 15:39
* @Version 1.0
**/
public class SocketClient {
public static void main(String[] args) throws IOException {
// 1 要连接的服务端IP地址和端口
String ip = "127.0.0.1";
int port = 55533;
// 2 创建客户端对象,与服务端建立连接
Socket socket = new Socket(ip, port);
// 3 建立连接后获得输出流
OutputStream outputStream = socket.getOutputStream();
String message = "你好 shiXinBing !!!";
outputStream.write(message.getBytes("UTF-8"));
System.out.println("消息已发送。。。。。");
// 4 关闭资源
outputStream.close();
socket.close();
}
}