进击的网络编程(二)

TCP通信原理

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,从而在通信的两端形成网络虚拟链路,一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信

JAva对基于TCP协议的网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过Socket产生IO流来进行网络通信

Java为客户端提供了Socket类,为服务器端提供了ServerSocket类

TCP发送数据

步骤:

  • ① 创建客户端的Socket对象
  • ② 获取输出流,写数据
  • ③ 释放资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package TCP_;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class ClientDemo {
public static void main(String[] args) throws IOException {
//Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。
Socket s=new Socket("yolin",4444);

//getOutputStream() 返回此套接字的输出流。
OutputStream os=s.getOutputStream();
os.write("hello,TCP!".getBytes());
s.close();
}

}

TCP接收数据

步骤:

  • ① 创建客户端的Socket对象
  • ② 获取输入流,读数据,并把数据显示在控制台
  • ③ 获取输入流,读数据,并把数据显示在控制台
  • ④ 释放资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package TCP_;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
public static void main(String[] args) throws IOException{
//ServerSocket(int port) 创建绑定到指定端口的服务器套接字。
ServerSocket ss=new ServerSocket(4444);
//accept() 侦听要连接到此套接字并接受它。
Socket s=ss.accept();
//获取输入流
InputStream is=s.getInputStream();
//字节流读数据
byte[] by=new byte[1024];
int len;
while((len=is.read(by))!=-1){
System.out.println(new String(by,0,len));

}
s.close();
ss.close();
}

}

练习一、服务器给出反馈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package TCP_;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

//客户端:发送数据,接收服务器反馈
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s=new Socket("yolin",2222);
//获取输出流,写数据
OutputStream os = s.getOutputStream();
os.write("helloTCP!".getBytes());
//接收服务器反馈
InputStream is = s.getInputStream();
byte[] bys=new byte[1024];
int len;
while((len=is.read(bys))!=-1){
System.out.println(new String(bys,0,len));
}
// int len=is.read(bys);
// String data=new String(bys,0,len);
// System.out.println(new String(by,0,len));
s.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package TCP_;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
//服务器:接收数据,给出反馈
public class ServerDemo {
public static void main(String[] args) throws IOException{
//创建服务器端socket对象
ServerSocket ss=new ServerSocket(2222);
//监听客户端连接,返回一个Socket对象
Socket s=ss.accept();
//获取输入流,读取数据
InputStream is=s.getInputStream();
byte[] by=new byte[1024];
int len;
while ((len=is.read(by))!=-1){
System.out.println("数据:"+new String(by,0,len));
}
//给出反馈
OutputStream os=s.getOutputStream();
os.write("数据已收到".getBytes());
ss.close();
}
}

练习二、客户端数据来自键盘录入

  • 客户端:数据来自键盘录入,知道输入的数据是886,发送数据结束
  • 服务器:接收到的数据在控制台输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package TCP_Scanner;

import java.io.*;
import java.net.Socket;

//客户端:数据来自键盘录入
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s=new Socket("yolin",2222);
//数据来自键盘录入
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line;
while((line=br.readLine())!=null){
if("886".equals(line)){
break;
}
//获取输出流对象
// OutputStream os=s.getOutputStream();
// os.write(line.getBytes());
bw.write(line);
bw.newLine();
bw.flush();
}

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package TCP_Scanner;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

//服务器:把收到的数据输出
public class ServerDemo {
public static void main(String[] args) throws IOException{
//创建服务器端socket对象
ServerSocket ss=new ServerSocket(2222);
//监听客户端连接,返回一个Socket对象
Socket s=ss.accept();
//获取输入流,读取数据
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line;
while((line=br.readLine())!=null){
System.out.println("数据是"+line);
}
s.close();
ss.close();
}
}

练习三、服务器数据写入文本文件

  • 客户端:数据来自键盘录入,知道输入的数据是886,发送数据结束
  • 服务器:接收到的数据写入文本文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package Server_Write;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

//服务器:把收到的数据输出写入文件
public class ServerDemo {
public static void main(String[] args) throws IOException{
//创建服务器端socket对象
ServerSocket ss=new ServerSocket(20000);
//监听客户端连接,返回一个Socket对象
Socket s=ss.accept();
//接收数据
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
//写入文件
BufferedWriter bw=new BufferedWriter(new FileWriter("message.txt"));
String line;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
ss.close();
}
}

练习四、客户端数据来自文本文件

  • 客户端:数据来自于文本文件
  • 服务器:接收到的数据写入文本文件

可以看作是文件的上传操作,总客户端发送到服务器上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 package Client_Write;

import java.io.*;
import java.net.DatagramSocket;
import java.net.Socket;

public class ClientDemo {
public static void main(String[]args) throws IOException {
//创建客户端对象
Socket s=new Socket("yolin",2222);

BufferedReader br=new BufferedReader(new FileReader("message.txt"));
//封装输出流写数据
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line;
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
s.close();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package Client_Write;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss=new ServerSocket(2222);
Socket s=ss.accept();
//接收数据
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter bw=new BufferedWriter(new FileWriter("message_copy.txt"));
String line;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
ss.close();
}
}

练习五、上传文件服务器给出反馈

  • 客户端:数据来自文本文件,接收服务器反馈
  • 服务器:接收到的数据写入文本文件,给出反馈
  • 出现问题:程序一直等待
  • 原因:读数据的方法是阻塞式的
  • 解决办法:自定义结束标记;使用shutdownOutput()方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package Server_back;

import java.io.*;
import java.net.Socket;

public class Client {
public static void main(String[] args) throws IOException {
Socket s=new Socket("yolin",3333);
//封装输出流写数据
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
BufferedReader br=new BufferedReader(new FileReader("message.txt"));
String line;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//添加标记 禁用此套接字的输出流。
s.shutdownOutput();

//接收服务器反馈
BufferedReader brclient=new BufferedReader(new InputStreamReader(s.getInputStream()));
String data=brclient.readLine();
System.out.println("服务器的反馈"+data);
brclient.close();
br.close();
s.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package Server_back;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss=new ServerSocket(3333);
Socket s=ss.accept();
//接收数据
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter bw=new BufferedWriter(new FileWriter("copy.txt"));
String line;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//给出反馈
BufferedWriter Serverbw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
Serverbw.write("文件上传成功");
Serverbw.newLine();
Serverbw.flush();
bw.close();
ss.close();
}
}

练习六、多线程实现文件上传

  • 客户端:数据来自文本文件,接收服务器反馈
  • 服务器:接收到的数据写入文本文件,给出反馈,代码用线程进行封装,为每个客户端开启一个线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package anli6;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss=new ServerSocket(4444);
while(true){
//监听客户端连接,返回一个对应的Socket对象
Socket s=ss.accept();
//为每一个客户端开启一个线程
ServerThread st=new ServerThread(s);
Thread t=new Thread(st);
t.start();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package anli6;

import java.io.*;
import java.net.Socket;

public class ServerThread implements Runnable{
private Socket s;
public ServerThread(Socket s) {
this.s=s;
}

@Override
public void run() {
//接收数据写到文本文件
try {
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
//解决文件名冲突
int count=0;
File file=new File("cpoy["+count+"].txt");
while(file.exists()){
count++;
file=new File("copy["+count+"].txt");
}
BufferedWriter bw=new BufferedWriter(new FileWriter(file));
String line;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//给出反馈
BufferedWriter Serverbw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
Serverbw.write("文件上传成功");
Serverbw.newLine();
Serverbw.flush();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package anli6;

import java.io.*;
import java.net.Socket;

public class Client {
public static void main(String[] args) throws IOException {
Socket s=new Socket("yolin",4444);
BufferedReader br=new BufferedReader(new FileReader("message.txt"));
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//自定义结束标记
s.shutdownOutput();
//接收反馈
BufferedReader Clientbr=new BufferedReader(new InputStreamReader(s.getInputStream()));
String data=Clientbr.readLine();
Clientbr.readLine();
System.out.println("接收到的服务器反馈:"+data);
br.close();
s.close();
}
}

请我喝杯咖啡吧~

支付宝
微信