一、網絡編程
1.軟件結構
CS結構:Client/Server 客戶端和服務端獨立
BS結構:Browser/Server 瀏覽器和服務端獨立
2.網絡通信
網絡通信協議指的就是多個計算機之間如果想實現通信,就必須遵守一定的規則
3.TCP協議和UDP協議
UDP協議:面向無連接。不區分客戶端和服務端的。發送數據效率快,但是數據不安全!而且有大小限制64KB
TCP協議:面向有連接。區分客戶端和服務端的。發送數據效率較慢。但是數據安全!沒有大小限制
4.網絡通信三要素
IP地址:每一臺電腦的唯一標示
端口號:是每一個軟件的標識,範圍:0--65535 常用的軟件端口號:網絡端口號80 MySQL3306 oracle1521 tomcat8080
通信協議:TCP協議和UDP協議
4.文件上傳步驟
客戶端:
a.首先創建Socket對象,指定IP與端口
b.創建一個本地輸入流(讀取文件),再創建一個網絡輸出流(通過Socket對象getOutputStream)
c.通過本地讀取流循環讀取並寫入到網絡輸出流中
d.一定要給服務器一個結束的標記 void shutdownOutput() 禁用此套接字的輸出流。
服務器端:
a.首先創建ServerSocket對象,指定IP端口
b.通過上面的對象調用accept()方法返回一個Socket對象
c.創建一個文件對象,指定文件客戶端上傳到的儲存路徑(爲了代碼的健壯性,建議對文件做一個判斷是否存在)
d.創建一個網絡輸入流(通過前面返回的Socket對象getInputStream),創建一個本地輸出流(將網絡輸出流裏面讀取的數據寫入到本地)
e.在通過Socket對象創建一個網絡輸出流(getOutputStream),寫一個提示反饋給客戶端write("傳輸成功".getBytes)
注意事項:
客戶端需要關閉 Socket對象和本地輸入流
服務器端需要關閉 ServerSocket對象
5.TCP協議的客戶端代碼實現
public class TCPClient {
public static void main(String[] args) throws IOException{
Socket s = new Socket("127.0.0.1",10086);
Scanner sc = new Scanner(System.in);
while(true) {
//獲取輸出流對象
OutputStream os = s.getOutputStream();
//寫出數據
System.out.println("請輸入給服務端發送的消息:");
String str = sc.nextLine();
os.write(str.getBytes());
//接收服務端發送過來的消息
//獲取輸入流對象
InputStream is = s.getInputStream();
byte[] arr = new byte[2048];
int len =is.read(arr);
System.out.println("從服務端接收到的消息是:");
System.out.println(new String(arr,0,len));
//釋放資源
//s.close();
}
}
}
6.TCP協議的服務端代碼實現
public class TCPServer {
public static void main(String[] args) throws IOException{
ServerSocket ss = new ServerSocket(10086);
Scanner sc = new Scanner(System.in);
//獲取服務端的Socket對象
Socket s = ss.accept();
while(true) {
//獲取輸入流對象
InputStream is = s.getInputStream();
byte[] arr = new byte[2048];
int len = is.read(arr);
System.out.println("從客戶端接收到的消息是:");
System.out.println(new String(arr,0,len));
//給客戶端回覆消息
//獲取輸出流對象
OutputStream os = s.getOutputStream();
System.out.println("請輸入給客戶端發送的消息:");
String str = sc.nextLine();
os.write(str.getBytes());
}
//釋放資源
//s.close();
// ss.close();
}
}
7.操作TCP協議的常見異常
ConnectException
出現原因:沒有開啓服務端。
解決方式:先開啓服務端,然後再開啓客戶端
BindException
出現原因:使用了已經被佔用的端口號
解決方式:換一個沒有被佔用的端口號
8.文件上傳案例-客戶端代碼
public class TCPClient {
public static void main(String[] args) throws IOException {
//1.創建一個本地字節輸入流FileInputStream對象,構造方法中綁定要讀取的數據源
FileInputStream fis = new FileInputStream("c:\\1.jpg");
//2.創建一個客戶端Socket對象,構造方法中綁定服務器的IP地址和端口號
Socket socket = new Socket("127.0.0.1",8888);
//3.使用Socket中的方法getOutputStream,獲取網絡字節輸出流OutputStream對象
OutputStream os = socket.getOutputStream();
//4.使用本地字節輸入流FileInputStream對象中的方法read,讀取本地文件
int len = 0;
byte[] bytes = new byte[1024];
while((len = fis.read(bytes))!=-1){
//5.使用網絡字節輸出流OutputStream對象中的方法write,把讀取到的文件上傳到服務器
os.write(bytes,0,len);
}
/*
解決:上傳完文件,給服務器寫一個結束標記
void shutdownOutput() 禁用此套接字的輸出流。
對於 TCP 套接字,任何以前寫入的數據都將被髮送,並且後跟 TCP 的正常連接終止序列。
*/
socket.shutdownOutput();
//6.使用Socket中的方法getInputStream,獲取網絡字節輸入流InputStream對象
InputStream is = socket.getInputStream();
//7.使用網絡字節輸入流InputStream對象中的方法read讀取服務回寫的數據
while((len = is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
//8.釋放資源(FileInputStream,Socket)
fis.close();
socket.close();
}
}
9.文件上傳案例-服務端代碼
public class TCPServer {
public static void main(String[] args) throws IOException {
//1.創建一個服務器ServerSocket對象,和系統要指定的端口號
ServerSocket server = new ServerSocket(8888);
//2.使用ServerSocket對象中的方法accept,獲取到請求的客戶端Socket對象
//4.判斷d:\\upload文件夾是否存在,不存在則創建
File file = new File("d:\\upload");
if(!file.exists()){
file.mkdirs();
}
/*
讓服務器一直處於監聽狀態(死循環accept方法)
有一個客戶端上傳文件,就保存一個文件
*/
while(true){
Socket socket = server.accept();
/*
使用多線程技術,提高程序的效率
有一個客戶端上傳文件,就開啓一個線程,完成文件的上傳
*/
new Thread(new Runnable() {
//完成文件的上傳
@Override
public void run() {
try {
//3.使用Socket對象中的方法getInputStream,獲取到網絡字節輸入流InputStream對象
InputStream is = socket.getInputStream();
/*
自定義一個文件的命名規則:防止同名的文件被覆蓋
規則:域名+毫秒值+隨機數
*/
String fileName = "itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";
//5.創建一個本地字節輸出流FileOutputStream對象,構造方法中綁定要輸出的目的地
//FileOutputStream fos = new FileOutputStream(file+"\\1.jpg");
FileOutputStream fos = new FileOutputStream(file+"\\"+fileName);
//6.使用網絡字節輸入流InputStream對象中的方法read,讀取客戶端上傳的文件
int len =0;
byte[] bytes = new byte[1024];
while((len = is.read(bytes))!=-1){
//7.使用本地字節輸出流FileOutputStream對象中的方法write,把讀取到的文件保存到服務器的硬盤上
fos.write(bytes,0,len);
}
//8.使用Socket對象中的方法getOutputStream,獲取到網絡字節輸出流OutputStream對象
//9.使用網絡字節輸出流OutputStream對象中的方法write,給客戶端回寫"上傳成功"
socket.getOutputStream().write("上傳成功".getBytes());
//10.釋放資源(FileOutputStream,Socket,ServerSocket)
fos.close();
socket.close();
}catch (IOException e){
System.out.println(e);
}
}
}).start();
}
//服務器就不用關閉
//server.close();
}
}
文本文件上傳
public class TCPClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 520);
//創建一個本地讀取流,因爲是txt文件,所以使用高效字符流,txt文件是在windows創建的,默認爲GBK格式
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("f:\\Test\\1.txt"),"GBK"));
//創建一個網絡輸出流,也是用高效輸出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"GBK"));
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
//給個結束標記
socket.shutdownOutput();
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(520);
//創建一個網絡讀取流 需要用到轉換 流
BufferedReader br = new BufferedReader(new InputStreamReader(server.accept().getInputStream(),"GBK"));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("f:\\Test\\22.txt"),"GBK"));
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.flush();
}
br.close();
server.close();
}
}
網絡編程、Socket、ServerSocket
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.