文章目录
1 网络编程
1.1 网络编程的概述
-
计算机网络
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。 -
网络编程
就是用来实现网络上互联的不同计算机上运行的程序之间的数据的交换。
1.2 网络模型
-
研究的就是计算机网络之间是以何种规则进行通信的。
-
网络模型一般指:
osi(open System Interconnection)开放系统互联参考模型 7层
TCP/IP 参考模型 4层
-
物理层:物理层处于OSI的最底层,是整个开放系统的基础。物理层涉及通信信道上传输的原始比特流(bits),功能主要是为数据端设备提供传送数据的通路以及传输数据。比如网线接口,光纤接口类型
-
数据链路层:主要任务是实现计算机网络中相邻节点之间的可靠传输,把原始的、有差错的物理传输线路加上数据链路协议以后,构成逻辑上可靠的数据链路。需要完成的功能有链路管理、成帧、差错控制以及流量控制等。其中成帧是对物理层的原始比特流进行界定,数据链路层也能够对帧的丢失进行处理。
-
网络层:把从下层接收的数据进行ip地址的封装和解封装,这层的数据叫做数据报。网络层涉及源主机节点到目的主机节点之间可靠的网络传输,它需要完成的功能主要包括路由选择、网络寻址、流量控制、拥塞控制、网络互连等。
-
传输层:定义传输协议和端口号。 传输层起着承上启下的作用,涉及源端节点到目的端节点之间可靠的信息传输。传输层需要解决跨越网络连接的建立和释放,对底层不可靠的网络,建立连接时需要三次握手,释放连接时需要四次挥手。
协议:TCP协议(Transmission Control Protocol,传输控制协议) 效率低,可靠。建立传输通道,在通道中传输数据,主要用来传输可靠性要求高的 数据量大的数据 UDP协议(User Datagram Protocol,用户数据报协议) 效率高,不可靠。不需要建立通道。主要用来传输可靠性要求低,数据量比较小的数据。 比如:qq 微信 。。。
端口号:应用程序的唯一标识。
这层的要功能是把下层的数据进行分段和发送。这层的数据一般叫做 段 -
会话层:通过传输层(端口号)建立数据传输通路。负责应用程序之间建立、维持和中断会话,同时也提供对设备和结点之间的会话控制,协调系统和服务之间的交流,并通过提供单工、半双工和全双工3种不同的通信方式,使系统和服务之间有序地进行通信。
-
表示层:对数据进行解码或者编码 。对数据类型解释,加密或者解密。压缩或者解压缩等。主要功能是把应用层提供的信息变换为能够共同理解的形式,提供字符代码、数据格式、控制信息格式、加密等的统一表示。
-
应用层:应用层为OSI的最高层,是直接为应用进程提供服务的。其作用是在实现多个系统应用进程相互通信的同时,完成一系列业务处理所需的服务。指的就是电脑上的应用程序。 比如 qq 微信 历览器 游戏
1.3 网络通信三要素
- ip地址:
网络中的标识符 - 端口号:
应用程序的标识符。 - 传输协议:
规则
常用的规则:tcp udp
1.4 ip地址
-
要让网络中的计算机能够互相通信,必须给每个计算机指定一个标识符
通过这个标识符来确定要接收数据的计算机,以及发送数据的计算机。
在TCP/IP ,这个标识就叫做 ip地址。 -
我们如何获取和操作ip地址呢?
为了方便对ip地址的获取和操作,java就给我们提供了一个类:InetAddress 供我们使用 -
ip地址其实就是给链接在互联网上的计算机分配的一个32bit地址。
按照TCP/IP 规定,ip地址用二进制来表示。每个ip地址的长是 32 bit 4个字节
11000000 10101000 00011111 00001010 但是这个太长,记忆还是处理都不方便。
所以ip地址就被改写成了十进制形式。中间用 . 隔开,于是ip地址就变成了地下这个样子
192.168.31.10
ip地址的这种表示方法称为 点分十进制表示法。 -
ip地址的组成:
ip地址 = 网络号码+主机号码
-ip地址的分类:
a类:第一段是网络号码,后三段是主机号码
b类:前二段是网络号码,后二段是主机号码
c类:前三段是网络号码,后一段是主机号码
- 特殊地址: 127.0.0.1 可以用来测试本机网络是否有问题 ping 127.0.0.1
xxx.xxx.xxx.0 网络地址
xxx.xxx.xxx.255 广播地址 - 私有地址:用于局域网
1.5 InetAddress类
- 此类表示Internet协议(IP)地址。
- 没有构造,里面有静态方法可以获取该类对象
static InetAddress getByName(String host) 确定主机名称的IP地址。
String getHostAddress()
返回文本显示中的IP地址字符串。
String getHostName()
获取此IP地址的主机名。
package com.momo.demo;
import java.net.InetAddress;
import java.net.UnknownHostException;
/*
* InetAddress类
* */
public class Demo11 {
public static void main(String[] args) throws UnknownHostException {
// InetAddress ip = InetAddress.getLocalHost();
// InetAddress ip = InetAddress.getByName("DESKTOP-EVP3D5Q");
InetAddress ip = InetAddress.getByName("192.168.31.10");
System.out.println(ip.getHostAddress());
System.out.println(ip.getHostName());
}
}
1.6 端口号
- 物理端口: 网卡口
- 逻辑端口: 我们现在说的就是这个
- 每个网络应用程序都至少会有一个逻辑端口
- 用来标识进程的逻辑地址。不同进程的标识符
- 有效端口号: 0-65535 其中0-1024基本上都被系统使用了或者是保留了。
1.7 传输协议
tcp
✔ 使用TCP协议前,须先建立TCP连接,形成传输数据通道
✔ 传输前,采用“三次握手”方式,点对点通信,是可靠的
✔ TCP协议进行通信的两个应用进程:客户端、服务端。
✔ 在连接中可进行大数据量的传输
✔ 传输完毕,需释放已建立的连接,效率低
udp
✔ 将数据、源、目的封装成数据包,不需要建立连接
✔ 每个数据报的大小限制在64K内
✔ 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
✔ 可以广播发送
✔ 发送数据结束时无需释放资源,开销小,速度快
1.7.1 TCP协议(Transmission Control Protocol,传输控制协议)
效率低,可靠。建立传输通道,在通道中传输数据,主要用来传输可靠性要求高的
数据量大的数据。需要经过3次握手才能完成链接。
TCP协议采用字节流传输数据
- TCP报文段格式
TCP报文段包括协议首部和数据两部分,协议首部的固定部分有20个字节,首部的固定部分后面是选项部分。
- 源端口号以及目的端口号,各占2个字节,端口是传输层和应用层的服务接口,用于寻找发送端和接收端的进程,一般来讲,通过端口号和IP地址,可以唯一确定一个TCP连接,在网络编程中,通常被称为一个socket接口。
- 序号,占4字节,用来标识从TCP发送端向TCP接收端发送的数据字节流。
- 确认序号,占4字节,包含发送确认的一端所期望收到的下一个序号,因此,确认序号应该是上次已经成功收到数据字节序号加1.
- 数据偏移,占4位,用于指出TCP首部长度,若不存在选项,则这个值为20字节,数据偏移的最大值为60字节。
- 保留字段占6位,暂时可忽略,值全为0
- 标志位
URG(紧急) : 为1时表明紧急指针字段有效
ACK(确认):为1时表明确认号字段有效
PSH(推送):为1时接收方应尽快将这个报文段交给应用层
RST(复位):为1时表明TCP连接出现故障必须重建连接
SYN(同步):在连接建立时用来同步序号
FIN (终止): 为1时表明发送端数据发送完毕要求释放连接 - 接收窗口占2个字节,用于流量控制和拥塞控制,表示当前接收缓冲区的大小。在计算机网络中,通常是用接收方的接收能力的大小来控制发送方的数据发送量。TCP连接的一端根据缓冲区大小确定自己的接收窗口值,告诉对方,使对方可以确定发送数据的字节数。
- 校验和占2个字节,范围包括首部和数据两部分。
- 选项是可选的,默认情况是不选。
- 三次握手与四次挥手
TCP是面向连接的协议,因此每个TCP连接都有3个阶段:连接建立、数据传送和连接释放。连接建立经历三个步骤,通常称为“三次握手”。
- 第一步,请求端(客户端)发送一个包含SYN标志的TCP报文,SYN即同步(Synchronize),同步报文会指明客户端使用的端口以及TCP连接的初始序号;
- 第二步,服务器端在收到客户端的SYN报文后,将返回一个SYN+ACK的报文,表示客户端的请求被接受,同时TCP序号被加一,ACK即确认(Acknowledgment)。
- 第三步,客户端也返回一个确认报文ACK给服务器端,同样TCP序列号被加一,到此一个TCP连接完成。
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
1.TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
2.服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
3.服务器关闭客户端的连接,发送一个FIN给客户端。
4.客户端发回ACK报文确认,并将确认序号设置为收到序号加1。
1.7.2 UDP协议(User Datagram Protocol,用户数据报协议)
效率高,不可靠。不需要建立通道。主要用来传输可靠性要求低,数据量比较小的数据。
把数据和目的地封装成数据包,每个数据包的大小限制在 64kb。
它由两部分组成:首部和数据。其中,首部仅有8个字节,包括源端口和目的端口,长度(UDP用于数据报的长度)、校验和。
2 Socket
2.1 Socket套接字
- 网络上具有唯一标识的ip地址和端口号组合到一起构成的一个唯一能识别的标识符套接字。
2.2 原理:
- 通信的2端都要有Socket
- 网络通信其实就是Socket之间的通信
- 数据在2个Socket之间通过流传输
3 UDP协议(发送数据和接收数据)
3.1 发送数据
-DatagramSocket DatagramPacket
UDP协议发送数据
package com.momo.demo;
import java.io.IOException;
import java.net.*;
/*
* UDP协议发送数据:
* 步骤:
* 创建发送端Socket对象
* 创建数据,把数据打包
* 调用socket对象的发送方法发送数据包
* 释放资源
* */
public class SendDemo {
public static void main(String[] args) throws IOException {
//UDP协议的Socket对象是 DatagramSocket
//DatagramSocket()构造数据报套接字并将其绑定到本地主机上的任何可用端口。
DatagramSocket ds = new DatagramSocket();
//DatagramPacket(byte[] buf, int length, InetAddress address, int port)
//构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号。
byte[] bys = "hello".getBytes();
int len = bys.length;
InetAddress it = InetAddress.getByName("192.168.31.10");
int port = 6666;
DatagramPacket dp = new DatagramPacket(bys,len,it,port);
//void send(DatagramPacket p)
//从此套接字发送数据报包。
ds.send(dp);
ds.close();
}
}
3.2 接收数据
UDP协议j接收数据
package com.momo.demo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/*
* UDP协议接收数据
* 步骤:
* 创建接收端Socket对象
* 创建一个数据包(接收数据的容器)
* 调用socket对象的接收方法来接收
* 解析数据包,获取数据
* 释放资源
注意:不能多次起启动接收端
* java.net.BindException: Address already in use: Cannot bind
* 端口号被占用了
* */
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//DatagramSocket(int port)
//构造数据报套接字并将其绑定到本地主机上的指定端口。
DatagramSocket ds = new DatagramSocket(6666);
//DatagramPacket(byte[] buf, int length)
//构造一个 DatagramPacket用于接收长度的数据包 length 。
byte[] bys = new byte[1024];
int len = bys.length;
DatagramPacket dp = new DatagramPacket(bys,len);
//void receive(DatagramPacket p)
//从此套接字接收数据报包。
ds.receive(dp);
//解析 使用dp中的方法获取数据
//ip
String ip = dp.getAddress().getHostAddress();
//端口号
int port = dp.getPort();
//获取数据
byte[] data = dp.getData();
//获取数据的实际长度
int i = dp.getLength();
//把字节数组转成字符串
String s = new String(bys,0,i);
System.out.println(ip+":"+port+":"+s);
ds.close();
}
}
3.3 练习
从键盘输入数据进行发送,当输入88时结束输入
package com.momo.demo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.util.Scanner;
public class SendDemo2 {
public static void main(String[] args) throws IOException {
//Scanner sc = new Scanner(System.in);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
DatagramSocket ds = new DatagramSocket();
String s = null;
while ((s=br.readLine())!=null){
//while ((s=sc.nextLine())!=null){
if(s.equals("88")){
break;
}
byte[] bys = s.getBytes();
DatagramPacket dp = new DatagramPacket(bys,bys.length, InetAddress.getByName("192.168.31.10"),8888);
ds.send(dp);
}
ds.close();
}
}
package com.momo.demo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveDemo2 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(8888);
while (true){
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys,bys.length);
ds.receive(dp);
System.out.println(dp.getAddress().getHostAddress()+":"+dp.getPort()+":"+new String(dp.getData(),0,dp.getLength()));
}
//接收端应该一直开着
//ds.close();
}
}
- 使用多线程改进上面的案例,实现在一个窗口发送和接收数据
4 TCP协议发送和接收数据
4.1 TCP协议发送数据
- Socket 该类实现客户端套接字(也称为“套接字”)。
-
创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务端的通信路线。若连接失败,则会出现异常。
-
打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输
-
按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入路线的信息),通过输出流将信息写入线程
-
关闭 Socket:断开客户端到服务器的连接,释放线路
package com.momo.demo;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/*
* TCP协议发送数据
* 步骤:
* 创建发送端的socket对象
* 这一步如果成功,就表示链接建立成功。
* 获取输出流,写数据
* 释放资源
注意:java.net.ConnectException: Connection refused: connect
* 链接异常,链接不成功。
* */
public class ClientDemo {
public static void main(String[] args) throws IOException {
//Socket(InetAddress address, int port)
//创建流套接字并将其连接到指定IP地址的指定端口号。
//Socket s = new Socket(InetAddress.getByName("192.168.31.10"),9999);
Socket s = new Socket("192.168.31.10",9999);
//OutputStream getOutputStream()
//返回此套接字的输出流。
OutputStream os = s.getOutputStream();
os.write("xiaojiejie".getBytes());
s.close();
}
}
4.2 TCP协议接收数据
- ServerSocket 这个类实现了服务器套接字
-
调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口 上。用于监听客户端的请求。
-
调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信 套接字对象。
-
调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出 流和输入流,开始网络数据的发送和接收。
-
关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。
package com.momo.demo;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
* TCP协议接收数据
* 步骤:
* 创建接收端的socket对象
* 监听客户端的链接。返回一个对应的客户端socket对象。
* 获取输入流读取数据
* 释放资源
* */
public class ServerDemo {
public static void main(String[] args) throws IOException {
//ServerSocket(int port)
//创建绑定到指定端口的服务器套接字。
ServerSocket ss = new ServerSocket(9999);
//Socket accept()
//侦听要连接到此套接字并接受它。
Socket s = ss.accept();//阻塞式
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys);
String str = new String(bys,0,len);
String ip = s.getInetAddress().getHostName();
int port = s.getPort();
System.out.println(ip+":"+port+":"+str);
s.close();
// ss.close(); 服务器不应该关闭
}
}
4.3 练习
- 客户端发送数据给服务端之后,服务端给客户端返回一个反馈信息
package com.momo.demo;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo2 {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086);
Socket s = ss.accept();
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
is.read(bys);
String str = new String(bys,0,bys.length);
System.out.println(str);
OutputStream os = s.getOutputStream();
os.write("你好客户端".getBytes());
s.close();
}
}
package com.momo.demo;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class ClientDemo2 {
public static void main(String[] args) throws IOException {
Socket s = new Socket("192.168.31.10",10086);
OutputStream os = s.getOutputStream();
os.write("服务器你好".getBytes());
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
is.read(bys);
String str = new String(bys,0,bys.length);
System.out.println(str);
s.close();
}
}
- 客户端使用键盘数据数据,服务器接收输出到文本文件。
package com.momo.demo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo3 {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10010);
Socket s = ss.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = null;
while ((str=br.readLine())!=null){
System.out.println(str);
}
s.close();
}
}
package com.momo.demo;
import java.io.*;
import java.net.Socket;
public class ClientDemo3 {
public static void main(String[] args) throws IOException {
Socket s = new Socket("192.168.31.10",10010);
//包装键盘输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//包装通道内的字节流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String str = null;
while ((str=br.readLine())!=null){
if(str.equals("88")){
break;
}
bw.write(str);
bw.newLine();
bw.flush();
}
s.close();
br.close();
bw.close();
}
}
- TCP简单C/S通信
package com.tony.networkprogramming.tcp;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTest {
/* 客户端 */
@Test
public void client(){
OutputStream output = null;
Socket socket = null;
try {
InetAddress localhost = InetAddress.getByName("192.168.137.1");
socket = new Socket(localhost, 8848);
output = socket.getOutputStream();
output.write("hello, I am the client".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (output != null){
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/* 服务端 */
@Test
public void server(){
ServerSocket serverSocket = null;
Socket socket = null;
InputStream input = null;
ByteArrayOutputStream out = null;
try {
serverSocket = new ServerSocket(8848);
socket = serverSocket.accept();
System.out.println("client IP: " + socket.getInetAddress());
input = socket.getInputStream();
out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) != -1){
out.write(buffer,0,len);
}
System.out.println(out.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(input != null){
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(serverSocket != null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
- TCP实现C/S文件传输
package com.tony.networkprogramming.tcp;
import org.junit.Test;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPSocketTest {
/* 客户端 */
@Test
public void client() {
Socket socket = null;
OutputStream output = null;
BufferedInputStream bis = null;
try {
socket = new Socket(InetAddress.getByName("192.168.137.1"), 8089);
output = socket.getOutputStream();
bis = new BufferedInputStream(new FileInputStream(new File("晴天.mp3")));
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1) {
output.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (output != null) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/* 服务端 */
@Test
public void server() throws IOException {
ServerSocket serverSocket = new ServerSocket(8089);
System.out.println("正在等待客户端连接...");
Socket socket = serverSocket.accept();
System.out.println("客户端已连接IP地址为:"+socket.getInetAddress().getHostAddress());
InputStream input = socket.getInputStream();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("a.mp3")));
byte[] bytes = new byte[1024];
int len;
while ((len=input.read(bytes))!=-1){
bos.write(bytes,0,len);
}
System.out.println("接收成功");
socket.close();
serverSocket.close();
input.close();
bos.close();
}
}
- TCP实现C/S信息反馈
package com.tony.networkprogramming.tcp;
import org.junit.Test;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPSocketTest2 {
/* 客户端 */
@Test
public void client() {
Socket socket = null;
OutputStream writer = null;
BufferedInputStream bis = null;
try {
socket = new Socket(InetAddress.getByName("127.0.0.1"),8089);
writer = socket.getOutputStream();
bis = new BufferedInputStream(new FileInputStream(new File("晴天.mp3")));
byte[] buffer = new byte[1024];
int len;
while((len = bis.read(buffer)) != -1){
writer.write(buffer,0,len);
}
// 关闭数据的输出
socket.shutdownOutput();
// 接收服务端反馈的信息并输出到控制台
InputStream is = socket.getInputStream();
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
byte[] buf = new byte[10];
int l;
while((l = is.read(buf)) != -1){
byteArray.write(buf,0,l);
}
System.out.println(byteArray.toString());
is.close();
byteArray.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis != null){
try {
bis.close();
System.out.println("发送成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/* 服务端 */
@Test
public void server() throws IOException { // 这里异常应该使用try-catch-finally
ServerSocket socket = new ServerSocket(8089);
System.out.println("正在等待客户端连接...");
Socket clientSocket = socket.accept();
System.out.println("客户端已连接IP地址为:"+clientSocket.getInetAddress().getHostName());
InputStream is = clientSocket.getInputStream();
BufferedOutputStream reader = new BufferedOutputStream(new FileOutputStream(new File("qingtian.mp3")));
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
reader.write(buffer,0,len);
}
System.out.println("接收成功");
// 服务端给客户端反馈信息
OutputStream os = clientSocket.getOutputStream();
os.write("你好客户端,照片已经收到".getBytes());
socket.close();
clientSocket.close();
is.close();
reader.close();
os.close();
}
}