(請觀看本人博文 —— 《詳解 網絡編程》)
ServerSocket與Socket
首先,本人來講解下 ServerSocket 類:
ServerSocket 類:
概述:
這個類實現了服務器套接字
該類是遵循 TCP協議的,所以,必須要和客戶端Socket建立連接,才能完成信息的接送
服務器套接字等待來自網絡的請求。
它基於該請求執行某些操作,然后可能向請求者返回結果。
服務器套接字的實際工作由SocketImpl類的一個實例進行。
一個應用程序可以更改創建套接字實現的套接字工廠,
以配置自己創建適合本地防火牆的套接字
那么,本人再來展示下這個類的構造方法:
構造方法:
- ServerSocket()
創建一個綁定服務器套接字- ServerSocket(int port)
創建一個服務器套接字,綁定到指定的端口- ServerSocket(int port, int backlog)
創建一個服務器套接字,並將其綁定到指定的本地端口號,並使用指定的積壓- ServerSocket(int port, int backlog, InetAddress bindAddr)
用指定的端口創建一個服務器,聽積壓,和本地IP地址綁定
現在,本人再來展示下這個類的API:
API:
- Socket accept()
監聽要對這個套接字作出的連接並接受它- void bind(SocketAddress endpoint)
ServerSocket綁定到一個特定的地址(IP地址和端口號)- void bind(SocketAddress endpoint, int backlog)
ServerSocket綁定到一個特定的地址(IP地址和端口號)- void close()
關閉這個套接字。- ServerSocketChannel getChannel()
返回與此套接字關聯的獨特的 ServerSocketChannel對象,如果任何- InetAddress getInetAddress()
返回此服務器套接字的本地地址- int getLocalPort()
返回此套接字正在偵聽的端口號- SocketAddress getLocalSocketAddress()
返回此套接字綁定到的端點的地址- int getReceiveBufferSize()
得到這個 ServerSocket的 SO_RCVBUF期權的價值,即該緩沖區的大小,將用於接受來自這 ServerSocket插座- boolean getReuseAddress()
如果 SO_REUSEADDR啟用- int getSoTimeout()
檢索設置 SO_TIMEOUT- protected void implAccept(Socket s)
子類使用此方法重載ServerSocket()返回自己的子類的插座- boolean isBound()
返回的ServerSocket綁定狀態- boolean isClosed()
返回的ServerSocket關閉狀態- void setPerformancePreferences(int connectionTime, int latency, int bandwidth)
設置此ServerSocket性能偏好- void setReceiveBufferSize(int size)
設置一個默認值為提出接受這 ServerSocket插座 SO_RCVBUF選項- void setReuseAddress(boolean on)
啟用/禁用 SO_REUSEADDR套接字選項- static void setSocketFactory(SocketImplFactory fac)
設置服務器套接字實現工廠為應用程序。- void setSoTimeout(int timeout)
啟用/禁用 SO_TIMEOUT以指定的超時時間,以毫秒為單位- String toString()
返回此套接字作為 String實現的地址與端口
由於該類必須與Socket類對象建立連接后才能進行正常的網絡通信,所以,本人在講解完Socket類之后再來展示部分API的使用。
Socket類:
概述:
這個類實現了客戶端套接字(也被稱為“套接字”)
該類遵循TCP協議,所以必須與ServerSocket建立連接后,才能進行信息的接送
套接字是兩台機器之間的通信的一個端點
套接字的實際工作是由該類的一個實例進行SocketImpl
一個應用程序,通過改變創建套接字實現的套接字工廠,可以配置自己創建適合本地防火牆的套接字
現在,本人來展示下這個類的構造方法:
構造方法:
- Socket()
創建一個連接的套接字,與socketimpl系統默認的類型。- Socket(InetAddress address, int port)
創建一個流套接字,並將其與指定的IP地址中的指定端口號連接起來。- Socket(InetAddress host, int port, boolean stream)
過時的。
使用UDP傳輸DatagramSocket。- Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
創建一個套接字,並將其與指定的遠程端口上的指定的遠程地址連接起來。- Socket(Proxy proxy)
創建一個連接的套接字類型,指定代理,如果有,應該使用無論任何其他設置。- protected Socket(SocketImpl impl)
創建一個用戶指定的socketimpl連接插座。- Socket(String host, int port)
創建一個流套接字,並將其與指定的主機上的指定端口號連接起來。- Socket(String host, int port, boolean stream)
過時的。
使用UDP傳輸DatagramSocket。- Socket(String host, int port, InetAddress localAddr, int localPort)
創建一個套接字,並將其連接到指定的遠程端口上的指定的遠程主機上
那么,本人再來展示下這個類的API:
API:
- void bind(SocketAddress bindpoint)
將套接字綁定到本地地址。- void close()
關閉這個套接字。- void connect(SocketAddress endpoint)
將此套接字連接到服務器。- void connect(SocketAddress endpoint, int timeout)
將此套接字與指定的超時值連接到服務器。- SocketChannel getChannel()
返回與此套接字關聯的獨特的 SocketChannel對象,如果任何。- InetAddress getInetAddress()
返回套接字連接的地址。- InputStream getInputStream()
返回此套接字的輸入流。- boolean getKeepAlive()
如果 SO_KEEPALIVE啟用。- InetAddress getLocalAddress()
獲取綁定的套接字的本地地址。- int getLocalPort()
返回此套接字綁定的本地端口號。- SocketAddress getLocalSocketAddress()
返回此套接字綁定到的端點的地址。- boolean getOOBInline()
如果 SO_OOBINLINE啟用。- OutputStream getOutputStream()
返回此套接字的輸出流。- int getPort()
返回此套接字連接的遠程端口號。- int getReceiveBufferSize()
得到這個 Socket的 SO_RCVBUF選項的值,是由平台用於該 Socket輸入緩沖區的大小。- SocketAddress getRemoteSocketAddress()
返回此套接字連接的端點的地址,或如果它是無關的 null。- boolean getReuseAddress()
如果 SO_REUSEADDR啟用。- int getSendBufferSize()
得到這個 Socket的 SO_SNDBUF期權價值,即緩沖區的大小由平台用於輸出在這 Socket。- int getSoLinger()
返回設置 SO_LINGER。- int getSoTimeout()
返回設置 SO_TIMEOUT。- boolean getTcpNoDelay()
如果 TCP_NODELAY啟用。- int getTrafficClass()
獲取從這個套接字發送的數據包的IP頭中的業務類或服務類型- boolean isBound()
返回套接字的綁定狀態。- boolean isClosed()
返回套接字的關閉狀態。- boolean isConnected()
返回套接字的連接狀態。- boolean isInputShutdown()
返回套接字連接的讀半是否關閉。- boolean isOutputShutdown()
返回套接字連接的寫是否關閉的是否關閉。- void sendUrgentData(int data)
在套接字上發送一個字節的緊急數據。- void setKeepAlive(boolean on)
啟用/禁用 SO_KEEPALIVE。- void setOOBInline(boolean on)
啟用/禁用 SO_OOBINLINE(TCP緊急數據收據)默認情況下,此選項是禁用TCP套接字上接收緊急數據是默默丟棄。- void setPerformancePreferences(int connectionTime, int latency, int bandwidth)
設置此套接字的性能首選項。- void setReceiveBufferSize(int size)
集 SO_RCVBUF選項,這 Socket指定值。- void setReuseAddress(boolean on)
啟用/禁用 SO_REUSEADDR套接字選項。- void setSendBufferSize(int size)
設置這個 Socket指定值的 SO_SNDBUF選項。- static void setSocketImplFactory(SocketImplFactory fac)
設置客戶端套接字實現工廠的應用程序。- void setSoLinger(boolean on, int linger)
啟用/禁用 SO_LINGER與指定的逗留的時間秒。- void setSoTimeout(int timeout)
啟用/禁用 SO_TIMEOUT以指定的超時時間,以毫秒為單位。- void setTcpNoDelay(boolean on)
啟用/禁用 TCP_NODELAY(禁用/啟用Nagle的算法)。- void setTrafficClass(int tc)
集交通類或從該套接字發送數據包的IP報頭字節型服務。- void shutdownInput()
將此套接字的輸入流放在“流結束”中。- void shutdownOutput()
禁用此套接字的輸出流。- String toString()
將這一 String插座
那么,現在,本人來通過兩個例子來展示下這兩個類的使用:
例1:
題目:
這天右轉哥玩游戲的時候,意外發現了游戲的一個Bug,於是,就向游戲公司發送信息,准備上報這個Bug
要求:
編寫一個服務器端的代碼,再編寫一個客戶端的代碼,完成客戶端向服務器端的Bug上報
那么,本人來展示下代碼:
首先是服務器端的代碼:
package edu.youzg.about_net.about_tcp.core;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(6666);
System.out.println("服務器已經開啟,等待連接。。。");
Socket sk = ss.accept();
//循環讀取客戶端發來的消息
while (true){
InputStream in = sk.getInputStream();
String ip = sk.getInetAddress().getHostAddress();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String s = new String(bytes, 0, len);
if(s.equals("byebye")){
break;
}
System.out.println(ip+":給你發來消息內容是:"+s);
}
ss.close();
}
}
現在是客戶端的代碼:
package edu.youzg.about_net.about_tcp.core;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws IOException {
//客戶端鍵盤錄入服務器控制台輸出
Socket sk = new Socket("localhost", 6666);
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
while (true){
System.out.println("請輸入消息");
String msg= bfr.readLine();
//發送給服務端
OutputStream out= sk.getOutputStream();
out.write(msg.getBytes());
if ("byebye".equals(msg)) {
break;
}
}
//釋放資源
bfr.close();
}
}
那么,現在,本人再來展示下運行結果:
首先是客戶端的控制台:
接下來是服務器端的控制台:
例2:
題目:
有一個壁紙很好康,右轉哥的兩個朋友十分想要,但是在網上找不到,朋友電腦上只有能運行Java程序的App,所以只能求右轉哥想辦法
要求:
通過網絡編程所學知識,將目標圖片傳送至那兩個朋友的電腦上
首先是 一個能夠上傳文件的線程實現類:
package edu.youzg.about_net.upload_file.core;
import java.io.*;
import java.net.Socket;
public class ServerThread extends Thread{
Socket sk;
public ServerThread(Socket sk) {
this.sk=sk;
}
@Override
public void run() {
try {
InputStream in = sk.getInputStream();
OutputStream out = sk.getOutputStream();
BufferedWriter bfw = new BufferedWriter(new FileWriter(System.currentTimeMillis() + "copyFile.txt")); //由於本人只有一台電腦,所以就將文件名跟事件相關
//包裝一下輸入流
BufferedReader bfr = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = bfr.readLine()) != null) {
bfw.write(line);
bfw.newLine();
bfw.flush();
}
//告訴客戶端,文件上傳成功
out.write("文件上傳成功".getBytes());
bfw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
那么,本人先來展示下右轉哥要運行的代碼:
package edu.youzg.about_net.upload_file.core;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) throws IOException {
//服務器告訴瀏覽器上傳成功了
ServerSocket ss = new ServerSocket(5555);
System.out.println("服務器已經開啟。。。");
int i=1;
while (true){
Socket sk = ss.accept(); //偵聽客戶端
System.out.println((i++)+"個客戶端已經連接");
//為每一個客戶端,開啟一個線程,去處理
new ServerThread(sk).start();
}
}
}
接下來,本人再來展示下兩個朋友要運行的代碼:
package edu.youzg.about_net.upload_file.core;
import java.io.*;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws IOException {
//給服務上傳一個文本文件
Socket socket = new Socket("localhost", 5555);
//獲取通道中的輸入輸出流
InputStream in= socket.getInputStream();
OutputStream out = socket.getOutputStream();
//讀取文本文件
BufferedReader bfr = new BufferedReader(new FileReader("test.txt"));
String line=null;
//把通道中的輸出流包裝一下
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(out));
while ((line=bfr.readLine())!=null){
bfw.write(line);
bfw.newLine();
bfw.flush();
}
//禁用此套接字的輸出流。
socket.shutdownOutput();
//讀取服務端反饋
byte[] bytes = new byte[1024];
int len = in.read(bytes);//阻塞式方法
String s = new String(bytes, 0, len);
System.out.println(s);
//釋放資源
bfr.close();
socket.close();
}
}
那么,現在,本人來展示下運行結果:
首先,本人來展示下源文件的目錄信息和源文件內容:
現在,本人來展示下運行后所生成的文件和該文件的內容:
那么,可以看到,我們將文件上傳成功了!
(本人 網絡編程 總集篇博文鏈接:https://www.cnblogs.com/codderYouzg/p/12419011.html)