api有哪些 javasocket_socket及socket java api
wiki上對于soket的定義
1.起源:
起源于https://tools.ietf.org/html/rfc147
2.套接字主要是在Internet模型的傳輸層中使用的概念。路由器和交換機等網絡設備一般不需要傳輸層的實現,因為它們一般在鏈路層(交換機)或互聯網層(路由器)上運行。
3.類型
數據報套接字,也稱為無連接套接字,使用用戶數據報協議(UDP)。
流套接字,也稱為面向連接的套接字,使用傳輸控制協議(TCP),流控制傳輸協議(SCTP)或數據報擁塞控制協議(DCCP)。
原始套接字(或原始IP套接字),通常在路由器和其他網絡設備中可用。這里繞過傳輸層,并且應用程序可以訪問包頭,并且地址中沒有端口號,只有IP地址。
廣義:socket有兩種場景。
本篇重點:網絡套接字以及Java關于socket api
首先回顧7層網絡模型
10dfa9ec8a1363270baa4fcb9b8fa0ec09fac787.jpg
由上面socket類型所知,socket主要是傳輸層的概念,主要也就是udp,和tcp兩種情況。(另外一種暫不討論)
先看下api
實例代碼:
try {
new Socket("127.0.0.1",80);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
1.常用構造器
public Socket(InetAddress address, int port) throws IOException {
this(address != null ? new InetSocketAddress(address, port) : null,
(SocketAddress) null, true);
}
private Socket(SocketAddress address, SocketAddress localAddr,
boolean stream) throws IOException {
setImpl();
// backward compatibility
if (address == null)
throw new NullPointerException();
try {
createImpl(stream);
if (localAddr != null)
bind(localAddr);
connect(address);
} catch (IOException | IllegalArgumentException | SecurityException e) {
try {
close();
} catch (IOException ce) {
e.addSuppressed(ce);
}
throw e;
}
}
1.以上構造器創建了一個IP Socket Address ,基于ip協議的SocketAddress(IP address + port number)
public InetSocketAddress(InetAddress addr, int port) {
holder = new InetSocketAddressHolder(
null,
addr == null ? InetAddress.anyLocalAddress() : addr,
checkPort(port));
}
2.創建SocksSocketImpl
void setImpl() {
if (factory != null) {
impl = factory.createSocketImpl();
checkOldImpl();
} else {
// No need to do a checkOldImpl() here, we know it's an up to date
// SocketImpl!
impl = new SocksSocketImpl();
}
if (impl != null)
impl.setSocket(this);
}
createImpl 即SocksSocketImpl::createImpl
SocksSocketImpl是AbstractPlainSocketImpl的子類,最終看AbstractPlainSocketImpl的createImpl。由代碼可知,最終的socket創建是由AbstractPlainSocketImpl創建的。如果是tcp,create(boolean stream)參數為true;如果是udp,參數為false。
/**
* Creates a socket with a boolean that specifies whether this
* is a stream socket (true) or an unconnected UDP socket (false).
*/
protected synchronized void create(boolean stream) throws IOException {
this.stream = stream;
if (!stream) {
ResourceManager.beforeUdpCreate();
// only create the fd after we know we will be able to create the socket
fd = new FileDescriptor();
try {
socketCreate(false);
} catch (IOException ioe) {
ResourceManager.afterUdpClose();
fd = null;
throw ioe;
}
} else {
fd = new FileDescriptor();
socketCreate(true);//子類PlainSocketImpl調用native void socketCreate(boolean isServer) throws IOException;
}
if (socket != null)
socket.setCreated();
//這里的socket,即開始new 的socket(“127.0.0.1”,80)對象
if (serverSocket != null)
serverSocket.setCreated();
}
3.在接著回到開始創建socket的代碼:創建完socket,接著校驗地址是否是IP4或ip6格式,校驗端口是否有權限(如果端口不允許訪問,會拋異常SecurityException),接著就開始bind遠程地址,并開始connect。
if (localAddr != null)
bind(localAddr);
connect(address);
bind最終調用的是SocksSocketImpl,即PlainSocketImpl的本地方法
getImpl().bind (addr, port);
protected synchronized void bind(InetAddress address, int lport)
throws IOException
{
synchronized (fdLock) {
if (!closePending && (socket == null || !socket.isBound())) {
NetHooks.beforeTcpBind(fd, address, lport);
}
}
socketBind(address, lport);//PlainSocketImpl 的native void socketBind(InetAddress address, int port)
throws IOException;
if (socket != null)
socket.setBound();
if (serverSocket != null)
serverSocket.setBound();
}
接著看connect
public void connect(SocketAddress endpoint) throws IOException {
connect(endpoint, 0);
}
//關鍵代碼
//再次校驗ip地址等
.....
else if (timeout == 0) {
if (epoint.isUnresolved())
impl.connect(addr.getHostName(), port);
else
impl.connect(addr, port);
} else
throw new UnsupportedOperationException("SocketImpl.connect(addr, timeout)");
connected = true;
bound = true;
上面連接的流程,默認timeout為0,直接連接,不支持超時。
改過程為阻塞的。( The connection will then block until established or an error occurs.)
protected void connect(String host, int port)
throws UnknownHostException, IOException
{
boolean connected = false;
try {
InetAddress address = InetAddress.getByName(host);
this.port = port;
this.address = address;
connectToAddress(address, port, timeout);
connected = true;
} finally {
if (!connected) {
try {
close();
} catch (IOException ioe) {
/* Do nothing. If connect threw an exception then
it will be passed up the call stack */
}
}
}
}
最終也是AbstractPlainSocketImpl調用子類PlainSocketImpl的本地方法socketConnect,來連接。
4.服務端socket創建, ServerSocket和Socket是完全相干的兩個類。
但是他們的初始化,共同點:如果指定端口,都會在初始化的時候嘗試bind本地端口,并判斷該端口是否有權限。區別:Socket如果初始化指定了(IP,port)除了bind外,會多一步connect的操作。
new ServerSocket(80);
public
class ServerSocket implements java.io.Closeable
public ServerSocket(int port) throws IOException {
this(port, 50, null);
}
ServerSocket(port)默認隊列大小50.當超過50的連接會被拒絕。
getImpl().bind(epoint.getAddress(), epoint.getPort());
getImpl().listen(backlog);
bound = true;
結下來看,accept():阻塞的,除非接收到一個連接。
步驟:創建一個unconnected Socket,并調用implAccept(s)
* Listens for a connection to be made to this socket and accepts
* it. The method blocks until a connection is made.
*
*
A new Socket {@code s} is created and, if there
* is a security manager,
* the security manager's {@code checkAccept} method is called
* with {@code s.getInetAddress().getHostAddress()} and
* {@code s.getPort()}
* as its arguments to ensure the operation is allowed.
* This could result in a SecurityException.
*
* @exception IOException if an I/O error occurs when waiting for a
* connection.
* @exception SecurityException if a security manager exists and its
* {@code checkAccept} method doesn't allow the operation.
* @exception SocketTimeoutException if a timeout was previously set with setSoTimeout and
* the timeout has been reached.
* @exception java.nio.channels.IllegalBlockingModeException
* if this socket has an associated channel, the channel is in
* non-blocking mode, and there is no connection ready to be
* accepted
public Socket accept() throws IOException {
if (isClosed())
throw new SocketException("Socket is closed");
if (!isBound())
throw new SocketException("Socket is not bound yet");
Socket s = new Socket((SocketImpl) null);
implAccept(s);
return s;
}
接下來,和客戶端socket一樣,默認新建SocksSocketImpl對象,并添加新的InetAddress對象
protected final void implAccept(Socket s) throws IOException {
SocketImpl si = null;
try {
if (s.impl == null)
s.setImpl();
else {
s.impl.reset();
}
si = s.impl;
s.impl = null;
si.address = new InetAddress();
si.fd = new FileDescriptor();
getImpl().accept(si);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccept(si.getInetAddress().getHostAddress(),
si.getPort());
}
} catch (IOException e) {
if (si != null)
si.reset();
s.impl = si;
throw e;
} catch (SecurityException e) {
if (si != null)
si.reset();
s.impl = si;
throw e;
}
s.impl = si;
s.postAccept();
}
/**
* Constructor for the Socket.accept() method.
* This creates an empty InetAddress, which is filled in by
* the accept() method. This InetAddress, however, is not
* put in the address cache, since it is not created by name.
*/
InetAddress() {
holder = new InetAddressHolder();
}
調用新建SocksSocketImpl的accept,即AbstractPlainSocketImpl的accept,如下:
/**
* Accepts connections.
* @param s the connection
*/
protected void accept(SocketImpl s) throws IOException {
acquireFD();
try {
socketAccept(s);//子類PlainSocketImpl的本地方法 native void socketAccept(SocketImpl s) throws IOException;
} finally {
releaseFD();//釋放fd
}
}
/*
* "Release" the FileDescriptor for this impl.
*
* If the use count goes to -1 then the socket is closed.
*/
void releaseFD() {
synchronized (fdLock) {
fdUseCount--;
if (fdUseCount == -1) {
if (fd != null) {
try {
socketClose();
} catch (IOException e) {
} finally {
fd = null;
}
}
}
}
}
題外話:
socket體系這里面涉及到了工廠的設計模式。方便內容的擴展。如果設置了factory,就按照自己設置的factory去實現
SocketImpl。代碼如下:
/**
* Sets impl to the system-default type of SocketImpl.
* @since 1.4
*/
void setImpl() {
if (factory != null) {
impl = factory.createSocketImpl();
checkOldImpl();
} else {
// No need to do a checkOldImpl() here, we know it's an up to date
// SocketImpl!
impl = new SocksSocketImpl();
}
if (impl != null)
impl.setSocket(this);
}
public
interface SocketImplFactory {
/**
* Creates a new {@code SocketImpl} instance.
*
* @return a new instance of {@code SocketImpl}.
* @see java.net.SocketImpl
*/
SocketImpl createSocketImpl();
}
public static synchronized void setSocketImplFactory(SocketImplFactory fac)
throws IOException
{
if (factory != null) {
throw new SocketException("factory already defined");
}
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkSetFactory();
}
factory = fac;
}
總結
以上是生活随笔為你收集整理的api有哪些 javasocket_socket及socket java api的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信用卡激活有效期是多久?这么做当心被交易
- 下一篇: echart移上去显示内容_echart