简单的TCP通信程序(二)

上次说了简单的TCP通信的代码实现,但是那是不完善的。只能进单次信息得交换,但是我们知道,一个服务器是可以和多个客户端进行通信得,所以,我们需要创建多线程。每有一个客户端发送信息服务器就会创建一个新的线程,从而实现多个客户端同时与服务器进行通信。

客户端

我们以传输一张图片为例

代码实现:

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
42
43
public class TCPClient {
public static void main(String[] args) throws Exception {

//创建一个本地字节输入流FileInputStream对象,构造方法中要绑定要读取的数据源
FileInputStream fis = new FileInputStream("E:\\text\\a.jpg");

//创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
//这里以本地IP为例,端口号为8888
Socket socket = new Socket("127.0.0.1",8888);

//使用Socket中的方法getOutputStream,获取网络字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();

//使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
int len = 0;
byte[] bytes = new byte[1024];
while ((len = fis.read(bytes)) != -1) {
//使用网络字节输出流OutputStream对象中的方法write,把读到的文件上传到服务器
os.write(bytes, 0, len);
}

/*
len = fis.read(bytes)并不会读到-1,所以,需要shutdownOutput()方法结束程序
void shutdownOutput() 禁用此套接字的输出流。
禁用此套接字的输出流。
对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列
*/
socket.shutdownOutput();

//使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象
InputStream is = socket.getInputStream();

//使用网络字节输入流InputStream对象中的read方法读取服务器回写的数据
while ((len = is.read(bytes)) != -1) {
System.out.println(new String(bytes,0,len));
}

//关闭资源
socket.close();
fis.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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class TCPServer {
public static void main(String[] args) throws IOException {
//创建一个服务器ServerSocket对象,和系统要指定的端口号
ServerSocket server = new ServerSocket(8888);

/*
让服务器一直处于监听状态(死循环accept方法)
有一个客户端上传文件,就保存一个
*/
while (true) {
//使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象
Socket socket = server.accept();

/*
使用多线程提高效率
有一个客户端上传文件,就开启一个线程
*/
new Thread(new Runnable() {

@Override
public void run() {
try {
//使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
InputStream is = socket.getInputStream();

//判断D:\\upload文件夹是否存在,不存在创建。 这个地址为服务器保存接收文件的地址,可以自行定义。
File file = new File("D:\\upload");
if (!file.exists()) {
file.mkdirs();
}
/*
自定义一个文件的命名规则,防止同名的文件被覆盖
规则 :域名+毫秒值+随机数

*/
String fileName = "itcast" + System.currentTimeMillis() + new Random().nextInt(999999) + ".jpg";

//创建一个本地字节输出流FileOutputStream对象,构造方法中绑定输出地址
// FileOutputStream fos = new FileOutputStream(file + "\\a.jpg");
FileOutputStream fos = new FileOutputStream(file + "\\" + fileName);
//使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件
int len = 0;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1) {
//使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
fos.write(bytes, 0, len);
}
//使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
//使用网络字节输出流OutputStream对象中的方法write,给客户端回写“上传成功“
socket.getOutputStream().write("上传成功".getBytes());
// 释放资源
fos.close();
socket.close();

} catch (IOException e) {
System.out.println(e);
}
}
}).start();


//服务器一直处于监听状态,所以不用关闭服务器,想要关闭,手动停止程序运行。

}
}
}

先运行服务器端,再运行客户端。