Socket是实现客户端套接字的类,套接字是两台计算机之间进行通信的端点。
Socket的实际工作由SocketImpl类的实例执行 。通过更改用于创建套接字实现的套接字工厂,应用程序可以配置自身以创建适合于本地防火墙的套接字。
//创建一个未连接的套接字,需要用相应成员方法进行连接才能使用。
public Socket()
//传入一个ip和端口进行创建套接字并进行连接
public Socket(String host, int port)
//传入一个InetAddress 对象和一个端口进行套接字创建并进行连接。InetAddress 是对要连接的地址进行封装的一个类。
public Socket(InetAddress address, int port)
//创建一个未连接的套接字,不过可以自定义套接字子类,实现特定功能
Socket(SocketImpl impl)
//建立套接字,可指定绑定本地的ip和端口,和要连接到的远程的IP和端口
//localAddr localPort 指定绑定本地ip和端口
//address port 指定要连接的远程ip和端口。
public Socket(InetAddress address, int port, InetAddress localAddr,int localPort)
//建立套接字,可指定绑定本地的ip和端口,和要连接到的远程的IP和端口
//localAddr localPort 指定绑定本地ip和端口
//host port 指定要连接的远程ip和端口。
public Socket(String host, int port, InetAddress localAddr, localPort)
/**
* 连接服务器套接字地址
* SocketAddress endpoint 要连接到的服务器套接字地址的封装。
*/
public void connect(SocketAddress endpoint)
/**
* 连接服务器套接字地址
* SocketAddress endpoint 要连接到的服务器套接字地址的封装。
* timeout 设置连接超时。
*/
public void connect(SocketAddress endpoint, int timeout)
/**
* 关闭套接字
*/
public synchronized void close()
/**
* 返回此套接字的输入流,也就是获取远程计算机连接传递过来的数据
*/
public InputStream getInputStream()
/**
* 返回此套接字的输出流,也就是此套接字要传输到远程连接到的套接字的数据流。
*/
public OutputStream getOutputStream()
//返回此套接字连接到的远程套接字的端口号,是远程套接字。
public int getPort()
//将套接字绑定到本地地址与端口 SocketAddress 是对套接字组成的抽象封装。
public void bind(SocketAddress bindpoint)
//返回套接字连接到的远程套接字的地址。
public InetAddress getInetAddress()
//获取是否空闲时像对方发送探测针用以确定对方连接是否关闭。
public boolean getKeepAlive()
//设置是否空闲时像对方发送探测针用以确定对方连接是否关闭。这里只是个开关,具体还是要看操作系统配置。
public void setKeepAlive(boolean on)
//获取套接字绑定到的本地地址
public InetAddress getLocalAddress()
//返回此套接字绑定到的本地端口号。
public int getLocalPort()
//返回此套接字绑定到的本地的套接字地址 SocketAddress 是对套接字地址的封装。
public SocketAddress getLocalSocketAddress()
//返回此套接字连接到的远程套接字的地址,未连接返回null值。
public SocketAddress getRemoteSocketAddress();
此类是实现服务器套接字。服务器套接字等待请求通过网络进入。它根据该请求执行一些操作,然后可能将结果返回给请求者。
服务器套接字的实际工作由SocketImpl该类的实例执行。应用程序可以更改创建套接字实现的套接字工厂,以将其自身配置为创建适合于本地防火墙的套接字。
//创建一个未绑定的服务器套接字。需要通过bind方法绑定
public ServerSocket()
//创建绑定到指定端口的服务器套接字。
public ServerSocket(int port)
//创建绑定到指定端口的服务器套接字。,并且可以指定积压连接数,也就是ServerSocket会有一个队列
//放置还没处理的socket连接,backlog就是设置该队列的容量,超出会拒绝连接。
public ServerSocket(int port, int backlog)
//创建具有指定端口的服务器,指定绑定的本地IP地址。设置积压连接数
public ServerSocket(int port, int backlog, InetAddress bindAddr)
//监听与此套接字建立的连接并接受它,这个方法会阻塞线程或者进程。知道有客户端连接过来,连接阻塞。
public Socket accept()
//关闭套接字。
public void close()
//将该套接字绑定到特定的本地ip和端口
public void bind(SocketAddress endpoint)
//将该套接字绑定到特定的本地ip和端口,设置积压连接数
public void bind(SocketAddress endpoint,int backlog)
//返回此服务器套接字的本地地址。
public InetAddress getInetAddress()
//返回此套接字正在监听的端口号。
public int getLocalPort()
//返回此套接字绑定到的端点的地址。
public SocketAddress getLocalSocketAddress()
//返回该套接字是否已经绑定
public boolean isBound()
//返回该套接字是否已经关闭
public boolean isClosed()
//服务端的代码。
public class ServerSocketDemo {
private static final int DEFAULT_PORT = 2510;
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
//建立服务监听,端口2510
serverSocket = new ServerSocket(DEFAULT_PORT);
System.out.println("端口:" + DEFAULT_PORT + "服务已启动");
while (true){
//监听连接,在客户端连接来临之前会处于阻塞状态。
Socket socket = serverSocket.accept();
//获取输入流。这个是从客户端传输过来的数据。
InputStream inputStream = socket.getInputStream();
//这里对输入的数据进行拆解
byte[] readContent = DataWrapper.wrapInputStreamData(inputStream);
System.out.println(new String(readContent));
//获取输出流。这个是要写到客户端的数据。
OutputStream outputStream = socket.getOutputStream();
byte[] writeContent = "请求已经收到,谢谢!".getBytes();
//对要写入到输出流的数据进行封装
byte[] writeData = DataWrapper.wrapOutputStreamData(writeContent);
//返回点信息给客户端
outputStream.write(writeData);
outputStream.flush();
//关闭socket,同时会关闭该socket的输出流和输入流。
socket.close();
}
}catch (IOException e){
e.printStackTrace();
}finally {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//客户端代码
public class SocketDemo {
public static void main(String[] args) {
try {
//建立客户端连接socket,此操作完成后,要连接到的服务监听就会接收到客户端连接并处理逻辑。
Socket socket = new Socket("127.0.0.1",2510);
//获取输出流。这个是要写到客户端的数据。
OutputStream outputStream = socket.getOutputStream();
byte[] content = "你好,ServerSocketDemo,我是SocketDemo".getBytes();
////对要写入到输出流的数据进行封装
byte[] writeByte = DataWrapper.wrapOutputStreamData(content);
//写入数据给服务端
outputStream.write(writeByte);
outputStream.flush();
//获取输入流。这个是从服务端传输过来的数据。
InputStream inputStream = socket.getInputStream();
//这里对输入的数据进行拆解
byte[] readContent = DataWrapper.wrapInputStreamData(inputStream);
System.out.println(new String(readContent));
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//////////////==============////工具类
/**
* @author YeHaocong
* @decription 对输出流和输入流的数据进行封装和拆解,因为socket流不能像文件数据流那样判断出是否到达数据流的结尾,所以
* @decription 要对写入到输出流的数据进行长度封装,封装在流的前四个字节里,然后处理输入流时对数据进行拆解。
*
*/
public class DataWrapper {
/**
* 对将要写到输出流数据进行封装
* @param writeData
* @return
*/
public static byte[] wrapOutputStreamData(byte[] writeData){
//得到数据的长度
int contentLen = writeData.length;
//将数据长度从int型转化为长度为4的字节数组。
byte[] contentLenByte = ByteArrayUtils.intToBytes(contentLen);
//将长度数组与数据数组合并,前面四个字节是长度数组
byte[] writeByte = ByteArrayUtils.mereTwoByteArray(contentLenByte,writeData);
return writeByte;
}
/**
* 对输入流的数据进行包装
* @param in
* @return
* @throws IOException
*/
public static byte[] wrapInputStreamData(InputStream in) throws IOException {
//4个长度的字节数组,用于存储输入流数据字节数组的前4个字节数据,该数据记录了输入流数据的长度。
byte[] readContentLenBytes = new byte[4];
in.read(readContentLenBytes);
//将字节数组转换成相应的int类型
int readContentLen = ByteArrayUtils.bytesToInt(readContentLenBytes);
//存储数据的数组
byte[] readContent = new byte[readContentLen];
in.read(readContent,0,readContentLen);
//返回不带前4个字节的真正的数据。
return readContent;
}
}
/**
* @author YeHaocong
* @decription 字节数组工具类
*
*/
public class ByteArrayUtils {
private static ByteBuffer buffer = ByteBuffer.allocate(4);
/**
* int类型转字节数组
* @param num
* @return
*/
public static byte[] intToBytes(int num) {
buffer.putInt(0, num);
return buffer.array();
}
/**
* 字节数组转int类型
* @param bytes
* @return
*/
public static int bytesToInt(byte[] bytes) {
buffer.put(bytes, 0, bytes.length);
buffer.flip();
return buffer.getInt();
}
/**
* 合并两个字节数组
* @param byteArr1 在新数组前面
* @param byteArr2 字新数组后面
* @return
*/
public static byte[] mereTwoByteArray(byte[] byteArr1,byte[] byteArr2){
byte[] result= new byte[byteArr1.length+byteArr2.length];
System.arraycopy(byteArr1, 0, result, 0, byteArr1.length);
System.arraycopy(byteArr2, 0, result, byteArr1.length, byteArr2.length);
return result;
}
}