TCP服务端实现
//定义服务器端socket并指定监听端口
ServerSocket serverSocket = new ServerSocket(5937);
//调用阻塞式方法来获取客户端连接的socket
Socket socket = serverSocket.accept();
//获取客户端socket的输入流
InputStream inputStream =socket.getInputStream();
//读取客户端socket的输入流的内容并输出
byte[]buffer = new byte[512];
inttemp;
while((temp = inputStream.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, temp));
}
TCP客户端实现
//产生socket对象,制定服务器地址和服务器监听的端口号
Socket socket = new Socket("127.0.0.1", 5937);
//获取socket的输出流
OutputStream outputStream =socket.getOutputStream();
//将数据放入输出流中
outputStream.write(msg.getBytes());
//定义服务器端socket并指定监听端口
ServerSocket serverSocket = new ServerSocket(5937);
//
java.net.ServerSocket.java96
/**
* Constructs a new {@code ServerSocket}instance bound to the given {@code localAddress}
* and {@code port}. The backlog is set to{@code backlog}.
* If {@code localAddress == null}, the ANYaddress is used.
* If {@code port == 0}, a port will beassigned by the OS.
*
* @throws IOException if an error occurs while creating the socket.
*/
public ServerSocket(int port, intbacklog, InetAddress localAddress) throwsIOException {
checkListen(port);
this.impl = factory != null ? factory.createSocketImpl()
: new PlainServerSocketImpl();
InetAddress addr = (localAddress == null) ? Inet4Address.ANY: localAddress;
synchronized (this) {
impl.create(true);
try {
impl.bind(addr,port);
readBackBindState();
impl.listen(backlog> 0 ? backlog : DEFAULT_BACKLOG);
} catch (IOException e) {
close();
throw e;
}
}
}
//
java:
FileDescriptor fd;
c++:
int fd;
int fd =jniGetFDFromFileDescriptor(env, javaFd);
定义:JNIHelp.cpp 320
FileDescriptor javaFd =jniCreateFileDescriptor(env, fd);
定义:JNIHelp.cpp 309
//
1.impl.create(true):
//
libcore.io.IoBridge.java606
public static FileDescriptor socket(boolean stream)
FileDescriptor fd;
fd = Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
(stream : true)
获得远端fd
→
libcore_io_posix.cpp 1419
static jobject Posix_socket(JNIEnv* env,jobject, jint domain, jint type, jint protocol)
socket(domain, type,protocol)
//
libcore.io.IoBridge.java376
private static voidsetSocketOptionErrno(FileDescriptor fd, int option, Object value)
Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR, booleanToInt((Boolean) value));
(value : Boolean.TRUE)
(booleanToInt((Boolean)value) : 1)
→
libcore_io_posix.cpp 1297
static void Posix_setsockoptInt(JNIEnv* env, jobject, jobject javaFd, jintlevel, jint option, jint value)
setsockopt(fd, level,option, &value, sizeof(value)))
//
2.impl.bind(addr, port):
libcore.io.IoBridge.java79
public static void bind(FileDescriptor fd,InetAddress address, int port)
Libcore.os.bind(fd, address, port);
→
libcore_io_posix.cpp 486
static void Posix_bind(JNIEnv* env, jobject, jobject javaFd, jobjectjavaAddress, jint port)
NET_FAIURE_RETRY(env, int, bind, javaFd, sa, sa_len);
宏定义:
bind(javaFd, sa, sa_len);
sa:
sockaddr_storage ss;
socklen_t sa_len;
inetAddressToSockaddr(env,javaAddress, port, ss, sa_len);
const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
//
3.readBackBindState():
InetAddress localAddress;
localAddress = IoBridge.getSocketLocalAddress(impl.fd);
获得本地IP端口
libcore.io.IoBridge.java627
public static InetAddress getSocketLocalAddress(FileDescriptor fd)
SocketAddress sa =Libcore.os.getsockname(fd);
→
libcore_io_posix.cpp 409
static jobject doGetSockName(JNIEnv* env,jobject javaFd, bool is_sockname)
sockaddr_storage ss;
sockaddr* sa = reinterpret_cast<sockaddr*>(&ss);
socklen_t byteCount = sizeof(ss);
getsockname(fd, sa,&byteCount)
//
4.impl.listen(backlog > 0 ? backlog : DEFAULT_BACKLOG):
java.net.PlainSocketImpl.java271
protected void listen(int backlog)
Libcore.os.listen(fd,backlog);
→
libcore_io_posix.cpp 965
static void Posix_listen(JNIEnv* env, jobject, jobject javaFd, jint backlog)
listen(fd, backlog);
backlog = DEFAULT_BACKLOG 50
//
//调用阻塞式方法来获取客户端连接的socket
Socket socket = serverSocket.accept();
//
/**
* Waits for an incoming request and blocksuntil the connection is opened.
* This method returns a socket objectrepresenting the just opened
* connection.
*
* @return the connection representing socket.
* @throws IOException
* if an error occurs while acceptinga new connection.
*/
public Socket accept() throwsIOException {
checkOpen();
if(!isBound()) {
throw new SocketException("Socket is not bound");
}
Socket aSocket = new Socket();
try {
implAccept(aSocket);
} catch (IOException e) {
aSocket.close();
throw e;
}
return aSocket;
}
1.isBound():
构造函数中readBackBindState() -> isBound = true;
2.implAccept(aSocket):
2.1.impl.accept(aSocket.impl):
(java.net.PlainSocketImpl.java80)
protected void accept(SocketImpl newImpl)
FileDescriptor clientFd =Libcore.os.accept(fd, peerAddress);
newImpl.fd.setInt$(clientFd.getInt$());
newImpl.address = peerAddress.getAddress();
newImpl.port = peerAddress.getPort();
获得对方远端IP端口
→
(libcore_io_posix.cpp460)
static jobject Posix_accept(JNIEnv* env,jobject, jobject javaFd, jobject javaInetSocketAddress)
jint clientFd =NET_FAIURE_RETRY(env, int, accept, javaFd, peer,peerLength);
宏定义:
accept(javaFd, peer,peerLength)
peer:
sockaddr_storage ss;
socklen_t sl = sizeof(ss);
memset(&ss, 0, sizeof(ss));
sockaddr* peer =(javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
socklen_t* peerLength =(javaInetSocketAddress != NULL) ? &sl : 0;
//
2.2.aSocket.accepted():
InetAddress localAddress;
localAddress = IoBridge.getSocketLocalAddress(impl.fd);
(获得对方本地IP端口)
同上1.3
//
//获取客户端socket的输入流
InputStream inputStream = socket.getInputStream();
//读取客户端socket的输入流的内容并输出
byte[] buffer= new byte[512];
int temp;
while ((temp = inputStream.read(buffer))!= -1) {
System.out.println(new String(buffer, 0, temp));
}
//
@Override protected synchronized InputStream getInputStream() throws IOException {
checkNotClosed();
return new PlainSocketInputStream(this);
}
private static class PlainSocketInputStream extends InputStream {
private final PlainSocketImpl socketImpl;
public PlainSocketInputStream(PlainSocketImpl socketImpl) {
this.socketImpl = socketImpl;
}
@Override public int available() throws IOException {
return socketImpl.available();
}
@Override public void close() throws IOException {
socketImpl.close();
}
@Override public int read() throws IOException {
return Streams.readSingleByte(this);
}
@Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
return socketImpl.read(buffer, byteOffset,byteCount);
}
}
/**
* For PlainSocketInputStream.
*/
private int read(byte[] buffer, int offset, int byteCount) throwsIOException {
if(byteCount == 0) {
return 0;
}
Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
if(shutdownInput) {
return -1;
}
int readCount = IoBridge.recvfrom(true, fd, buffer, offset, byteCount, 0, null, false);
// Return of zero bytes for a blocking socket means atimeout occurred
if(readCount == 0) {
throw new SocketTimeoutException();
}
// Return of -1 indicates the peer was closed
if(readCount == -1) {
shutdownInput = true;
}
return readCount;
}
(libcore.io.IoBridge.java549)
public static int recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected)
result = Libcore.os.recvfrom(fd, bytes, byteOffset, byteCount, flags,srcAddress);
→
(libcore_io_posix.cpp1185)
static jint Posix_recvfromBytes(JNIEnv*env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jintbyteCount, jint flags, jobject javaInetSocketAddress)
NET_FAIURE_RETRY(env,ssize_t, recvfrom, javaFd, bytes.get() + byteOffset, byteCount, flags, from, fromLength);
宏定义:
recvfrom(javaFd,bytes.get() + byteOffset, byteCount, flags, from, fromLength);
bytes : ScopedBytesRWbytes(env, javaBytes);
byteOffset : 0
flags : 0
from : BULL
fromLength : 0
问题:
为什么java tcp接收底层代码是recvfrom()而不是read()?