这里是Java网络编程
,Java Socket编程
相关的学习手记
。这里按照官方的Java 8 Toturial
教程的Custom Networking学习路径
,对相关的一些内容进行解读(并不完全,如果有错请联系我,谢谢^ _ ^),同时在学习的过程中加入个人的理解与对代码运行的思考。
下面是整个专栏的文章链接,用于快速的导航。
0
. 整个系列文章介绍1
. Java网络编程假定你需要一些基本的网络知识。2
. Java操作URL;java.net.URL,java.net.URLConnection3
. Java Socket编程;关于Socket的使用; java.net.Socket ,java.net.ServerSocket4
. Java UDP Datagrams数据报编程;Java单播,多播编程;java.net.DatagramPacket,java.net.DatagramSocket,java.net.MulticastSocket5
. 使用Java访问系统(电脑,机器)的网络信息,如网卡信息,网络状态等;java.net.NetworkInterface6
. 在Java客户端上操作,管理Cookie;7
. 在1~6节的编程实践中,我遇到的一些问题;
- 【网络编程】——Java实现(7)—— 1~6章的实践中常见问题集锦
当我们使用socket通信时,我们之前的例子全部都是使用readLine(),println()来读写一行string。但是现在我们想传输特定的基本数据类型的数据,该怎么办呢,下面就是解决方案:下面是单独的实践部分:不涵盖在Java Tutorial里:
8
. 数据传输需要注意点
导言
我们之前的案例中,我们传输时,一次性从socket上读写的数据都是一行string值。现在,我们想要更加精细地对
特定基本数据类型的数据的接收与发送
进行探讨。
我们所说的特定基本数据类型,指Java中的如下数据类型。
byte bt = 64;
char c = 'b';
int i = 123456;
boolean bool = true;
long l = 12345678;
float f = 12.345f;
double d = 12.345678;
这里我们使用的关键手段为java.nio.ByteBuffer
类。
下面先贴出代码,再进行说明:
Server类:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
public class Server {
public static final int LOCAL_PORT = 23334;
public static ByteBuffer byteBuffer = null;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = createSocket();
// 初始化socket的一些属性,参数
initSocket(serverSocket);
// bind
serverSocket.bind(new InetSocketAddress(Inet4Address.getLocalHost(), LOCAL_PORT));
System.out.println("服务器准备就绪...");
System.out.println("服务器信息, IP: " + serverSocket.getInetAddress() +
", Port: " + serverSocket.getLocalPort() );
while(true){
Socket clientSocket = serverSocket.accept();
new HandlerRequestSocket(clientSocket).start();
}
}
public static ServerSocket createSocket() throws IOException {
ServerSocket serverSocket = new ServerSocket();
return serverSocket;
}
public static void initSocket(ServerSocket socket){
// TODO initialize Socket
}
public static class HandlerRequestSocket extends Thread{
private Socket clientSocket;
public HandlerRequestSocket(Socket clientSocket) {
this.clientSocket = clientSocket;
}
@Override
public void run() {
super.run();
System.out.println("新客户端连接, IP: " + clientSocket.getInetAddress() + ", Port: " + clientSocket.getPort());
try {
OutputStream out = clientSocket.getOutputStream();
InputStream in = clientSocket.getInputStream();
// 创建一个ByteBuffer,并wrap socket接收的数据,
byte[] buffer = new byte[256];
int readCount = in.read(buffer);
getAndPrint(buffer, readCount);
// 返回数据给客户端,写
out.write(buffer, 0, readCount);
out.close();
in.close();
System.out.println("客户端退出, IP: " + clientSocket.getInetAddress() +
", Port: " + clientSocket.getPort() );
} catch (IOException e) {
e.printStackTrace();
System.err.println("连接异常...");
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void getAndPrint(byte[] buffer, int readCount){
byteBuffer = ByteBuffer.wrap(buffer);
byte bt = byteBuffer.get();
char c = byteBuffer.getChar();
int i = byteBuffer.getInt();
boolean bool = (byteBuffer.get() == 1 ? true : false);
long l = byteBuffer.getLong();
float f = byteBuffer.getFloat();
double d = byteBuffer.getDouble();
int pos = byteBuffer.position();
String str = new String(buffer, pos, readCount-pos-1);
System.out.println("收到数据: " + readCount + "Bytes. All data is followed: \n" +
"byte: " + bt + "\n" +
"char: " + c + "\n" +
"int: " + i + "\n" +
"bool: " + bool + "\n" +
"long: " + l + "\n" +
"float: " + f + "\n" +
"double: " + d + "\n" +
"String: " + str + "\n" );
}
}
Server类的总体代码框架为main中的代码:
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = createSocket();
// 初始化socket的一些属性,参数
initSocket(serverSocket);
// bind
serverSocket.bind(new InetSocketAddress(Inet4Address.getLocalHost(), LOCAL_PORT));
System.out.println("服务器准备就绪...");
System.out.println("服务器信息, IP: " + serverSocket.getInetAddress() +
", Port: " + serverSocket.getLocalPort() );
while(true){
Socket clientSocket = serverSocket.accept();
new HandlerRequestSocket(clientSocket).start();
}
}
先实例化一个ServerSocket
,再初始化此ServerSocket:initSocket(serverSocket);
(函数为空,只是示意一下代码框架
)。然后对socket进行绑定操作。接着一个while循环处理接收的数据。本文章主要的内容在getAndPrint函数
部分。
现在先不说明其作用,待下面我们将客户端的程序代码列出来之后,一起讲。
下面是Client类:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
public class Client {
public static final int LOCAL_PORT = 23333;
public static final int REMOTE_PORT = 23334;
public static ByteBuffer byteBuffer = null;
public static void main(String[] args) throws IOException {
Socket socket = createSocket();
initSocket(socket);
socket.connect(new InetSocketAddress(Inet4Address.getLocalHost(), REMOTE_PORT), 3000);
System.out.println("发起服务器连接...");
System.out.println("服务器信息, IP: " + Inet4Address.getLocalHost() + ", Port: " + REMOTE_PORT);
System.out.println("客户端信息, IP: " + Inet4Address.getLocalHost() + ", Port: " + LOCAL_PORT);
requestSocket(socket);
socket.close();
System.out.println("客户端退出...");
}
public static Socket createSocket() throws IOException {
Socket socket = new Socket();
socket.bind(new InetSocketAddress(Inet4Address.getLocalHost(), LOCAL_PORT));
return socket;
}
public static void initSocket(Socket socket){
// TODO initialize Socket
}
public static void requestSocket(Socket socket) throws IOException {
// to read
InputStream input = socket.getInputStream();
// to write
OutputStream out = socket.getOutputStream();
// 将buffer放到ByteBuffer里
byte[] buffer = new byte[256];
putByteBufferData(buffer);
// 发送信息,写socket
out.write(buffer, 0, byteBuffer.position()+1);
System.out.println("发送数据成功...");
out.close();
input.close();
}
public static void putByteBufferData(byte[] buffer){
// 发送不同类型的数据
byte bt = 64;
char c = 'b';
int i = 123456;
boolean bool = true;
long l = 12345678;
float f = 12.345f;
double d = 12.345678;
String str = "test测试";
// 将buffer放到ByteBuffer里
byteBuffer = ByteBuffer.wrap(buffer);
byteBuffer.put(bt);
byteBuffer.putChar(c);
byteBuffer.putInt(i);
byteBuffer.put(bool ? (byte) 1 : (byte)0);
byteBuffer.putLong(l);
byteBuffer.putFloat(f);
byteBuffer.putDouble(d);
byteBuffer.put(str.getBytes());
}
}
同样,对Server类的框架理解了,这里的代码框架了同样理解了。
下面说明ByteBuffer对基本数据类型的发送的实现。
我们使用ByteBuffer时,一般不会将socket获得的InputStream,OutputStream
进行封装获取BufferedReader
等高级的输入输出类对象。我们直接使用InputStream,OutputStream
。
一般性的操作:
byte[] buffer = new byte[256];
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
byteBuffer.putXX();
或者
byteBuffer.getXX()
XX
代码前面我们所列举的基本数据类型。
如果XX为空,那么就是byteBuffer.put()或byteBuffer.get()直接放入/获取一个byte的数据
很容易理解。