Java网络编程之TCP协议

目录

一、浅析TCP协议

二、什么是Socket?

三、案例—图片上传服务器端、客户端

四、拓展:Socket流

五、总结

一、浅析TCP协议

       TCP协议是建立在lP协议之上的,简单地说,IP协议只负责发数据包,不保证顺序和正确性,而TCP协议负责控制数据包传输,它在传输数据之前需要先建立连接,建立连接后才能传输数据,传输完后还需要断开连接。TCP协议之所以能保证数据的可靠传输,是通过接收确认、超时重传这些机制实现的。并且,TCP协议允许双向通信,即通信双方可以同时发送和接收数据。
       TCP协议也是应用最广泛的协议,许多高级协议都是建立在TCP协议之上的,例如HTTP 、SMTP等。

二、什么是Socket?

       在开发网络应用程序的时候,会遇到Socket 这个概念。Socket是一个抽象概念,一个应用程序通过一个 Socket来建立一个远程连接,而Socket内部通过TCP/IP协议把数据传输到网络。

┌───────────┐                                   ┌───────────┐
│Application│                                   │Application│
├───────────┤                                   ├───────────┤
│  Socket   │                                   │  Socket   │
├───────────┤                                   ├───────────┤
│    TCP    │                                   │    TCP    │
├───────────┤      ┌──────┐       ┌──────┐      ├───────────┤
│    IP     │<────>│Router│<─────>│Router│<────>│    IP     │
└───────────┘      └──────┘       └──────┘      └───────────┘

       Java提供的几个Socket相关的类就封装了操作系统提供的接口:ServerSocket类、Socket类。

       为什么需要Socket 进行网络通信?因为仅仅通过IP地址进行通信是不够的,同一台计算机同一时间会运行多个网络应用程序,例如浏览器、QQ、邮件客户端等。当操作系统接收到一个数据包的时候,如果只有IP地址,它没法判断应该发给哪个应用程序,所以,操作系统抽象出socket接口,每个应用程序需要各自对应到不同的Socket,数据包才能根据Socket 正确地发到对应的应用程序。

       使用Socket进行网络编程时,本质上就是两个进程之间的网络通信。其中一个进程必须充当服务器端,它会主动监听某个指定的端口,另一个进程必须充当客户端,它必须主动连接服务器的IP地址和指定端口,如果连接成功,服务器端和客户端就成功地建立了一个TCP连接,双方后续就可以随时发送和接收数据。

       因此,当Socket连接成功地在服务器端和客户端之间建立后:·对服务器端来说,它的 Socket是指定的IP地址和指定的端口号;·对客户端来说,它的Socket是它所在计算机的IP地址和一个由操作系统分配的随机端口号。

三、案例—图片上传服务器端、客户端

服务器端:

       要使用 Socket 编程,我们首先要编写服务器端程序。Java标准库提供了ServerSocket来实现对指定IP和指定端口的监听。

图片上传服务器端:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 图片文件服务器端
 */
public class ImageFileServer {
	public static void main(String[] args) {
		try {
			//ServerSocket:服务器进行通信的对象
			ServerSocket server = new ServerSocket(8808);
			
			//死循环:不断接收客户端的连接
			while(true) {
				//服务器进入"等待"状态
				//如果有客户端连接时,该方法返回此客户端的client
				Socket client = server.accept();
				InetAddress clientNetAddress = client.getInetAddress();
				System.out.println("客户端" + clientNetAddress.getHostAddress() + "开始连接。。。。");
				
				//接收来自客户端上传的图片
				//输入流:读取来自客户端发送的图片文件流
				//输出流:写入本地图片
				String imageName = clientNetAddress.getHostAddress().replaceAll("\\.", "-") + ".jpg";
				
				try(InputStream in = client.getInputStream();
				BufferedInputStream bis = new BufferedInputStream(in);
				BufferedOutputStream bos = new BufferedOutputStream(
						new FileOutputStream("E:\\test\\img\\" + imageName))){
					//每次读取来自客户端的图片文件流
					//写入本地
					byte[] buff = new byte[1024];
					int len = -1;
					while((len = bis.read(buff)) != -1) {
						bos.write(buff, 0, len);
					}
					
					System.out.println("图片读取完毕!!");
					
					//输出提示信息 => 客户端
					try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))){
						writer.write("upload success !");
						writer.newLine();
					}
					
					
				}
				
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

}

        服务器通过上述代码,在指定端口8808监听,如果ServerSocket监听成功,我们就使用一个无限循环来处理客户端的连接,注意到代码server.accept()表示每当有新的客户端连接进来后,就返回一个 socket实例,这个Socket实例就是用来和刚连接的客户端进行通信的。

       如果没有客户端连接进来,accept()方法会阻塞并一直等待。如果有多个客户端同时连接进来,Serversocket会把连接扔到队列里,然尼一个一个处理。对于Java程序而言,只需要通过循环不断调用accept()就可以获取新的连接。

客户端:

相比服务器端,客户端程序就简单许多

图片上传客户端:

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 上传图片客户端
 */
public class UploadImageClient {
	public static void main(String[] args) {
		//Socket:客户端进行通信的组件
		//本地图片读取 =>通过输出流(发送)至服务器
		//OutputStream:输出流,将读取到的本地图片文件流,发送(输出)至服务器
		//BufferedInputStream:输入流,读取本地图片
		try (Socket client = new Socket("192.168.254.137",8808);
			 OutputStream out = client.getOutputStream();
			 BufferedInputStream bis = new BufferedInputStream(
					 new FileInputStream("E:\\test\\girl.jpg"))
			 ){
			
			//每次读取1024个字节
			byte[] buff = new byte[1024];
			int len = -1;
			while((len = bis.read(buff)) != -1) {
				//将读取到的内容,通过输入流发送至服务器
				out.write(buff);
			}
			
			//"输出"暂时结束(Socket没有关闭)
			client.shutdownOutput();
			
			//读取来自服务器的反馈
			try(BufferedReader reader = new BufferedReader(
					new InputStreamReader(client.getInputStream()))){
				String reply = reader.readLine();
				System.out.println("服务器的反馈:  " + reply);
			}
			
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

   客户端程序通过下述代码,连接到服务器端,注意上述代码的服务器地址是"192.168.254.137",端口号是8808。如果连接成功,将返回一个Socket实例,用于后续通信。

四、拓展:Socket流

       当socket 连接创建成功后,无论是服务器端,还是客户端,我们都使用 Socket实例进行网络通信。因为TCP是一种基于流的协议,因此,Java标准库使用工nputstream和outputstream来封装 Socket的数据流,这样我们使用Socket的流,和普通IO流类似:

// 用于读取网络数据:
InputStream in = sock.getInputStream();

// 用于写入网络数据:
OutputStream out = sock.getOutputStream();

       写入网络数据时,必须要调用flush()方法。如果不调用flush(,我们很可能会发现,客户端和服务器都收不到数据,这并不是Java标准库的设计问题,而是我们以流的形式写入数据的时候,并不是一写入就立刻发送到网络,而是先写入内存缓冲区,直到缓冲区满了以后,才会一次性真正发送到网络,这样设计的目的是为了提高传输效率。如果缓冲区的数据很少,而我们又想强制把这些数据发送到网络,就必须调用flush()强制把缓冲区数据发送出去。

五、总结

使用Java进行TCP编程时,需要使用Socket模型:

·服务器端用ServerSocket监听指定端口;

·客户端使用socket(InetAddress, port)连接服务器;

·服务器端用accept()接收连接并返同Socket实例;

·服务器端通过使用多线程同时处理多个客户端连接,利用线程池可大幅提升效率;

. flush()方法用于强制输出缓冲区到网络。

以上就是对于基于TCP协议的网络编程知识分享,如有不当之处,还请大家多多评论指正,喜欢的话可以留下您的关注和点赞,一起学习,一起进步!


 

  • 18
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值