JAva IO学習ノート[2]
5117 ワード
私は昨日javaネットワークのプログラミングを書いたとき、このようないくつかの問題を考えました.今まとめます.
一:TCPプログラミングはバイトストリーム向け
私はsocketでプログラミングして、TCP/IPに基づいて、TCPプロトコルは伝送層のプロトコルで、それは接続に向いて、UDPと大きい違いは前者がバイトストリームに向かうプロトコルで、後者はユーザーデータグラムProtocolで、バイトストリームに向かって大きなメリットがあって、それは混雑制御を行うことができて、流量制御を行うことができて、エラーコントロールを行います.
なぜUDPがダメなのか?UDPアプリケーション層が伝送層にどんなデータ新聞を送信するか、伝送層がどんなデータ新聞を送信するか、それが何バイトあるかにかかわらず、伝送が多すぎるとブロックされるのではないか.TCPは違います.アプリケーション層が転送層にデータを転送させる場合、転送層は直接送信するのではなく、バッファから1バイトずつ取り出し、TCP送信端には送信ウィンドウがあります.このウィンドウはTCPが流量制御を行い、エラー制御のコアです.受信側には受信ウィンドウがあり、要するにウィンドウの直接的なスライド(速くなったり、順序が乱れたり、フレームが失われたり)によって、以上の制御が行われる.
ではjavaはsocketプログラミングを行うときにバイトストリームしか使えませんか?答えはそうじゃない
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.InputStream;
public class Server1 {
/** */
public static void main(String[] args) throws IOException{
ServerSocket ss = new ServerSocket(5678);
Socket socket = ss.accept();
PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(true)
{
String str=in.readLine();
System.out.println(str);
out.println("hello world");
out.flush();
}
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/**
* socket
* */
public class Client1
public static void main(String[] args)throws Exception{
Socket server=new Socket("localhost",5678);
BufferedReader in=new BufferedReader(new InputStreamReader(server.getInputStream()));
PrintWriter out=new PrintWriter(server.getOutputStream());
BufferedReader wt=new BufferedReader(new InputStreamReader(System.in));
while(true){
String str=wt.readLine();
out.println(str);
out.flush();
if(str.equals("end")){
break;
}
System.out.println(in.readLine());
}
server.close();
}
}
以上のコードは、文字ストリーム向けの仮想イメージを使用していますが、ここでは文字ストリームがバイトストリームをカプセル化していることがわかります.ここではアダプタモードであるべきで、1つのバイトストリームを1つの文字ストリームに変換し、server.getInputStream()メソッドのソースコードは、実際に返されるバイトストリームを見ることができます.
public InputStream getInputStream() throws IOException
二:printとprintlnの違いはいったい何ですか.
ソケットプログラミングでPrintWriterクラスを出力ストリームとして使用する場合、print()ではなくprintln(String str)が必要になる理由.
私の印象ではprintlnはprintの後ろに改行符をつけただけで、ほとんどの人が私の考えと同じだと思いますが、ソースコードを見てみると
/**
* Prints a String and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(String)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>String</code> to be printed.
*/
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
上記の2つの方法から少なくとも2点1:println方法はスレッドが安全であることがわかる:2:newLine()方法が1つ増えた.
ではnewLine()はどんな方法ですか?
/**
private BufferedWriter textOut;
*/
private void newLine() {
try {
synchronized (this) {
ensureOpen();
textOut.newLine();
// BufferedWriter newLine
/**
* Writes a line separator. The line separator string is defined by the
* system property <tt>line.separator</tt>, and is not necessarily a single
* newline ('
') character.
*
* @exception IOException If an I/O error occurs
*
public void newLine() throws IOException {
write(lineSeparator);
}
*/
/**
* Flushes the output buffer to the underlying character stream, without
* flushing the stream itself. This method is non-private only so that it
* may be invoked by PrintStream.
,
*/
textOut.flushBuffer();
/*
?
*/
charOut.flushBuffer();
if (autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
つまりprintlnメソッドはprintよりも多くのことをしています.改行を終了し、バッファをリフレッシュする機能がありますが、printはありません.print出力を使用すると、リフレッシュも終了もなく、単独で書き込まれます.
では、バッファをリフレッシュするには、いったい底で何をしたのでしょうか.