ハロー/ HI単純なネットワークチャットプログラム
0 LinuxのソケットAPI
バークレーソケットインタフェースは、アプリケーション・プログラミング・インターフェース(API)は、ホスト間またはコンピュータ間のプロセスが通信できるように、インターネットソケットの概念を使用します。これは、オペレーティング・システムの特定の実装に依存するが、それは、多くの異なる入力/出力デバイスと上記ドライバ上で実行することができます。TCP / IPプロトコル用のインタフェース、それはインターネットを維持するための基本的な技術の一つであるように。これは、Unixシステムのために、当初、カリフォルニア大学バークレー校が開発しました。今日では、すべての近代的なオペレーティング・システムは、ソケットインタフェースからいくつかの実現を持っている、それはインターネットに接続するための標準的なインターフェースとなっています。
私たちは、LinuxのソケットAPIは、ここではいくつかの一般的なTCPコネクションソケット・インタフェース機能を確立するために使用し、要約を特徴としている、実際にソケットです。
socket()
型、整数値識別(とタイプを決定するために新しいソケットを作成するファイル記述子)、及びそれに割り当てるシステムリソースを。bind()
通常、サーバー、構造に関連付けられたソケットアドレスのソケット、例えば、指定されたローカルポートとIPアドレス。listen()
サーバー側、そうで拘束TCPソケットTCP状態はCLOSE行くLISTENことを、このリスニングソケットサーバのTCPオペレーティングシステムのカーネルは、対応するソケット保留キューおよびキューESTABLISHEDソケットを作成し、バックログを保留中のパラメータを指定しますソケットキューの長さ、0は長さが無限であってもよい表します。ソケットを保留中、クライアントは、3ウェイハンドシェイクのSYNパケット到着され、カーネルはこれに対応するTCP SYN要求パケットとしてソケット(SYN_RECV状態)を生成しますが、ときソケット3ウェイハンドシェイクが完了していません。connect()
クライアントの場合、ソケットは空きポート番号がローカルで割り当てられます。それはTCPソケットである場合、それは新しいTCP接続を取得しようとします。accept()
サーバ側の場合。それは、新しいアクセスは、クライアントの遠位端部から送られたTCP接続要求を受け入れ、作成する新しいソケット、およびそれぞれのアドレスを接続するソケットを作成します。send()
そしてrecv()
、又はwrite()
及びread()
又はrecvfrom()
、およびsendto()
、ソケットに遠隔からデータを送受信するための/。close()
ソケットに割り当てられたリソースを解放するためのシステム。TCP場合は、接続が中断されます。
1つのハロー/ HIプログラム
1.0機能の概要
以下/ HIプログラムコードJava言語を使用するための簡単なハローを提供し、プログラムは、2つの部分、すなわち、サーバとクライアントに分かれています。プログラムは「こんにちは、私はクライアント」の文字列を送信するクライアントから始まる、TCPコネクションを確立するためのJavaソケットAPIを使用して、サーバは、サーバに「こんにちは、私はサーバー」の文字列を返します。
1.1サーバー
サーバーの機能は8090ポートをリスニングクラスのServerSocketのJavaのオブジェクトを使用して、受け入れたServerSocketクラスを(使用)8090ポートとの接続を確立するためにあるクライアントから受信したときに、「こんにちは、私はクライアントだ」、「こんにちはで応答し、私は次のようにコードは、「サーバー午前:
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket socket = new ServerSocket(8090);// 监听8090端口
System.out.println("TCP server ready.");
Socket sock = socket.accept();// 建立连接
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(sock.getInputStream(), StandardCharsets.UTF_8))) {
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(sock.getOutputStream(), StandardCharsets.UTF_8))) {
String cmd = reader.readLine();// 读取发送到服务端的数据
if ("Hi,I am Client".equals(cmd)) {
System.out.println("Client:"+cmd+"\n");
writer.write("Hi,I am Server"+ "\n");
writer.flush();
} else {
writer.write("require data\n");
writer.flush();
}
}
}
sock.close();// 关闭连接
socket.close();// 关闭监听端口
}
}
1.2クライアント
クライアント機能は、マシンのアドレスを取得した後、8090ローカル作成するためにポートを接続することです。サービスのメッセージ待ちを送信した後、サーバーの応答に「こんにちは、私はクライアントです」。
public class Client {
public static void main(String[] args) throws IOException {
InetAddress addr = InetAddress.getLoopbackAddress();// 获取本机地址,即“127.0.0.1”
try (Socket socket = new Socket(addr, 8090)) {// 与本机8090端口建立连接
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))) {
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8))) {
writer.write("Hi,I am Client\n");
writer.flush();
String resp = reader.readLine();// 读取本机8090端口返回的数据
System.out.println("Server: " + resp);
}
}
}
}
}
2 JavaのソケットAPIとLinuxのソケットAPIの間の関係を分析します
二つのプログラム上のコンストラクタとのServerSocketクラスを呼び出すclose()
だけでなく、コンストラクタSocketクラスaccept()
、 getInputStream()
` getOutputStream()
およびclose()
方法を。次に、ソースのServerSocketクラスとSocketクラスの分析は、JavaソケットAPIを見つけて、LinuxのソケットAPIを介して関係を対応します。
2.0のSocketImplクラス関係およびLinuxのソケットAPIの
抽象クラスのSocketImplは、実際の同等の、操作のSocketImplクラスが発見された場合、実際のソケットは、コアが論理的にLinuxのソケットAPIの対応を操作すると、抽象化して動作するすべてのクラスのソケット共通のスーパークラスを実装しています対応するLinuxのソケットAPI操作を見つけます。
2.1のServerSocketクラス
2.1.0 SeverSocket()
サーバプログラムでは、8090のServerSocketクラスオブジェクトのリスニングポートを構成します:
ServerSocket socket = new ServerSocket(8090);
対応するソースコードを検索:
public ServerSocket(int port) throws IOException {
this(port, 50, (InetAddress)null);
}
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
this.created = false;
this.bound = false;
this.closed = false;
this.closeLock = new Object();
this.oldImpl = false;
this.setImpl();
if (port >= 0 && port <= 65535) {
if (backlog < 1) {
backlog = 50;
}
try {
this.bind(new InetSocketAddress(bindAddr, port), backlog);
} catch (SecurityException var5) {
this.close();
throw var5;
} catch (IOException var6) {
this.close();
throw var6;
}
} else {
throw new IllegalArgumentException("Port value out of range: " + port);
}
あなたは、見ることができthis.bind(new InetSocketAddress(bindAddr, port), backlog);
文が呼び出すbind()
、メソッドをその具体的な実現を参照してください。
this.getImpl().bind(epoint.getAddress(), epoint.getPort());
this.getImpl().listen(backlog);
ディスカバリーSeverSocket.bind()
LinuxのソケットAPIのメソッドbind()
やlisten()
関数に相当します。
だから、ServerSocket()
LinuxのソケットAPI市の対応socket()
、bind()
、listen()
。
2.1.1)(受け入れます
サーバはまた、使用するServerSocket.accept()
以下のソースコードを見つけ、ソケットオブジェクトを初期化する方法。
public Socket accept() throws IOException {
if (this.isClosed()) {
throw new SocketException("Socket is closed");
} else if (!this.isBound()) {
throw new SocketException("Socket is not bound yet");
} else {
Socket s = new Socket((SocketImpl)null);
this.implAccept(s);
return s;
}
}
それに対応するLinuxのソケットAPI市を探しますaccept()
。
2.1.2近いです()
public void close() throws IOException {
synchronized(this.closeLock) {
if (!this.isClosed()) {
if (this.created) {
this.impl.close();
}
this.closed = true;
}
}
}
明らかに、ServerSocket.close()
対応するLinuxのソケットAPI市close()
。
2.2 Socketクラス
クライアントとサーバは接続して通信を確立するためTcpのSocketクラスのオブジェクトを構築しています。以下の分析でソース関数。
2.2.0ソケット()
クライアントとサーバーの使用コンストラクタそれぞれSocket(SocketImpl impl)
とSocket(InetAddress address, int port)
、実際には、前者はちょうどどのソースすることができます参照してくださいするには、オブジェクトSocketクラスのコピーです。
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 {
this.created = false;
this.bound = false;
this.connected = false;
this.closed = false;
this.closeLock = new Object();
this.shutIn = false;
this.shutOut = false;
this.oldImpl = false;
this.setImpl();
if (address == null) {
throw new NullPointerException();
} else {
try {
this.createImpl(stream);
if (localAddr != null) {
this.bind(localAddr);
}
this.connect(address);
} catch (IllegalArgumentException | SecurityException | IOException var7) {
try {
this.close();
} catch (IOException var6) {
var7.addSuppressed(var6);
}
throw var7;
}
}
}
このメソッドは、Socketクラスを呼び出すことが判明したbind()
とconnect()
方法を。
すでに知っているよると、ServerSocketのクラスのServerSocket.bind()
LinuxのソケットAPIの方法bind()
とlisten()
、それはとても対応であれば、関数対応し、その後、Socketクラス、?見Socket.bind()
:コア文の方法this.getImpl().bind(addr, port);
で見つかったSocket.bind()
だけで、対応するLinuxのソケットAPIの方法で対応bind()
。
Socket.connect()
次のようにコア文の方法は次のとおりです。
if (!this.oldImpl) {
this.impl.connect(epoint, timeout);
} else {
if (timeout != 0) {
throw new UnsupportedOperationException("SocketImpl.connect(addr, timeout)");
}
if (epoint.isUnresolved()) {
this.impl.connect(addr.getHostName(), port);
} else {
this.impl.connect(addr, port);
}
}
LinuxのソケットAPIに対応するディスカバリー機能がありますconnect()
。
、上記の分析から導かSocket()
LinuxのソケットAPI市のためにsocket()
、bind()
、connect()
。
2.2.1のgetInputStream()&のgetOutputStream()
前述のように、対応するソースコードを検索します:
public InputStream getInputStream() throws IOException {
if (this.isClosed()) {
throw new SocketException("Socket is closed");
} else if (!this.isConnected()) {
throw new SocketException("Socket is not connected");
} else if (this.isInputShutdown()) {
throw new SocketException("Socket input is shutdown");
} else {
InputStream is = null;
try {
is = (InputStream)AccessController.doPrivileged(new PrivilegedExceptionAction<InputStream>() {
public InputStream run() throws IOException {
return Socket.this.impl.getInputStream();
}
});
return is;
} catch (PrivilegedActionException var3) {
throw (IOException)var3.getException();
}
}
}
public OutputStream getOutputStream() throws IOException {
if (this.isClosed()) {
throw new SocketException("Socket is closed");
} else if (!this.isConnected()) {
throw new SocketException("Socket is not connected");
} else if (this.isOutputShutdown()) {
throw new SocketException("Socket output is shutdown");
} else {
OutputStream os = null;
try {
os = (OutputStream)AccessController.doPrivileged(new PrivilegedExceptionAction<OutputStream>() {
public OutputStream run() throws IOException {
return Socket.this.impl.getOutputStream();
}
});
return os;
} catch (PrivilegedActionException var3) {
throw (IOException)var3.getException();
}
}
}
それは見ることができるSocket.getInputStream()
とSocket.getOutputStream()
、対応するLinuxのJava APIは、あるrecv()
とsend()
。
2.2.2近いです()
public synchronized void close() throws IOException {
synchronized(this.closeLock) {
if (!this.isClosed()) {
if (this.created) {
this.impl.close();
}
this.closed = true;
}
}
}
同様に、Socket.close()
対応するLinuxのJavaのAPI市close()
。
3概要
上記の問い合わせから、次の表のJavaのソケットAPIとLinuxのソケットAPIとの関係:
JavaのソケットAPI | LinuxのソケットAPI |
---|---|
ServerSocket() |
socket() 、bind() 、listen() |
ServerSocket.accept() |
accept() |
ServerSocket.bind() |
bind() 、listen() |
ServerSocket.close() |
close() |
Socket() |
socket() 、bind() 、connect() |
Socket.bind() |
bind() 、connect() |
Socket.getInputStream() |
recv() |
Socket.getOutputStream() |
send() |
Socket.close() |
close() |
あなたが見ることができ、LinuxのソケットAPIのJavaソケットAPIは、さまざまな状況に応じてTCPコネクションやすくするために、さらにパッケージでした。
参考資料
https://www.cnblogs.com/abcboy/p/9769230.html
https://github.com/mengning/net
https://zh.wikipedia.org/wiki/Berkeley%E5%A5%97%E6%8E%A5%E5%AD%97