Java 网络编程系列② -- TCP网络编程
基于Socket的TCP编程
Java语言的基于套接字编程分为服务端编程和客户端编程,其通信模型如图所示:
从客户端来说
客户端Socket的工作过程包含以下四个基本的步骤:
- 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
- 打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用getOutputStream()方法获得输出流,进行数据传输
- 按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线程。
- 关闭 Socket:断开客户端到服务器的连接,释放线路
客户端创建Socket对象:
客户端程序可以使用Socket类创建对象,创建的同时会自动向服务器方发起连接,Socket的构造器是:
- Socket(String host,int port)throws UnknownHostException,IOException:向服务器(域名是host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。
- Socket(InetAddress address,int port)throws IOException:根据InetAddress对象所表示的IP地址以及端口号port发起连接。
从服务器来说
服务器程序的工作过程包含以下四个基本的步骤:
- 调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。
- 调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。
- 调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出流和输入流,开始网络数据的发送和接收。
- 关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。
服务器建立 ServerSocket 对象:
ServerSocket 对象负责等待客户端请求建立套接字连接,类似邮局某个窗口中的业务员。也就是说,服务器必须事先建立一个等待客户请求建立套接字连接的ServerSocket对象。
所谓“接收”客户的套接字请求,就是accept()方法会返回一个 Socket 对象
关于Socket的理解
这个我参考了其他博主的文章,我觉得写的非常清晰:
TCP网络编程例题
例题一
要求:客户端发送信息给服务端,服务端将数据显示在控制台上
代码实现:
//此为客户端
@Test
public void client() {
Socket kehu = null;
OutputStream words = null;
try {
//首先创建Socket(这个是指向服务器的)
kehu = new Socket("127.0.0.1",8989);
//开始传输信息
words = kehu.getOutputStream();
words.write("这里是客户端".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
}
//关闭流(使用try-catch)
if(words != null){
try {
words.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(kehu != null){
try {
kehu.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//此为服务端
@Test
public void server(){
ServerSocket receiver = null;
Socket receive = null;
InputStream shuru = null;
ByteArrayOutputStream box = null;
try {
//首先创建ServerSocket对相应端口进行监听
receiver = new ServerSocket(8989);
// 接收来自客户端的Socket
receive = receiver.accept();
//以此Socket创建输入流
shuru = receive.getInputStream();
//用ByteArrayOutputStream来接收,不建议使用byte型数组装然后再转为字符串,因为装满的时候
//正好有个字符的字节缺失
box = new ByteArrayOutputStream();
int len;
byte[] box1 = new byte[10];
while((len = shuru.read(box1)) != -1){
box.write(box1,0,len);
}
//将ByteArrayOutputStream缓冲区中的字节直接转化为字符串输出到控制台中
System.out.println(box.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
}
//关闭流
if(box != null){
try {
box.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (shuru != null){
try {
shuru.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(receive != null){
try {
receive.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(receiver != null){
try {
receiver.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
- 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
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
注:①在服务器端不建议使用
//不建议这样写,可能会有乱码
// byte[] buffer = new byte[1024];
// int len;
// while((len = is.read(buffer)) != -1){
// String str = new String(buffer,0,len);
// System.out.print(str);
// }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
②在服务器端使用了ByteArrayOutputStream的缓冲区去接收,而不是ByteArrayInputStream。
例题二
任务:客户端发送文件给服务端,服务端将文件保存在本地。
代码实现:
/*
这里涉及到的异常,应该使用try-catch-finally处理
*/
@Test
public void client() throws IOException {
//1.
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
//2.
OutputStream os = socket.getOutputStream();
//3.
FileInputStream fis = new FileInputStream(new File("beauty.jpg"));
//4.
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
os.write(buffer,0,len);
}
//5.
fis.close();
os.close();
socket.close();
}
/*
这里涉及到的异常,应该使用try-catch-finally处理
*/
@Test
public void server() throws IOException {
//1.
ServerSocket ss = new ServerSocket(9090);
//2.
Socket socket = ss.accept();
//3.
InputStream is = socket.getInputStream();
//4.
FileOutputStream fos = new FileOutputStream(new File("beauty1.jpg"));
//5.
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
//6.
fos.close();
is.close();
socket.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
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
例题三
任务:从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端。
代码实现:
/*
这里涉及到的异常,应该使用try-catch-finally处理
*/
@Test
public void client() throws IOException {
//1.
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
//2.
OutputStream os = socket.getOutputStream();
//3.
FileInputStream fis = new FileInputStream(new File("beauty.jpg"));
//4.
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
os.write(buffer,0,len);
}
//关闭数据的输出
socket.shutdownOutput();
//5.接收来自于服务器端的数据,并显示到控制台上
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[20];
int len1;
while((len1 = is.read(buffer)) != -1){
baos.write(buffer,0,len1);
}
System.out.println(baos.toString());
//6.
fis.close();
os.close();
socket.close();
baos.close();
}
/*
这里涉及到的异常,应该使用try-catch-finally处理
*/
@Test
public void server() throws IOException {
//1.
ServerSocket ss = new ServerSocket(9090);
//2.
Socket socket = ss.accept();
//3.
InputStream is = socket.getInputStream();
//4.
FileOutputStream fos = new FileOutputStream(new File("beauty2.jpg"));
//5.
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
System.out.println("图片传输完成");
//6.服务器端给予客户端反馈
OutputStream os = socket.getOutputStream();
os.write("你好,照片我已收到".getBytes());
//7.
fos.close();
is.close();
socket.close();
ss.close();
os.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
- 67
- 68
- 69
- 70
- 71
- 72
注意:客户端传完图片之后一定要关闭数据的输出(shutdownOutput()),如果不手动关闭,因为服务端接收时的read()方法是一种阻塞式的方法,他会一直等到客户端传输结束,但是这个信号一直没有来,他就会一直等。((len = is.read(buffer)) != -1并不能阻止这个情况的发生,因为read返回-1是代表到达流的末尾,而此时read是不能确定是否到达了流的末尾的,所以他才一直等)
文章来源: blog.csdn.net,作者:十八岁讨厌编程,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/zyb18507175502/article/details/122527727
- 点赞
- 收藏
- 关注作者
评论(0)