> 文章列表 > TCP和UDP网络编程

TCP和UDP网络编程

TCP和UDP网络编程

TCP和UDP协议是TCP/IP协议的核心。 TCP 传输协议:TCP 协议是一TCP (Transmission Control
Protocol)和UDP(User Datagram
Protocol)协议属于传输层协议。其中TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送;而UDP则不为IP提供可靠性、流控或差错恢复功能。一般来说,TCP对应的是可靠性要求高的应用,而UDP对应的则是可靠性要求低、传输经济的应用

1. 基于TCP的网络编程

IP是一个通信实体在网络上的地址,通信实体可以是打印机、计算机等。IP协议的作用是让Internet成为一个允许连接不同类型计算机和不同操作系统的网络。IP协议负责将消息从一个主机传到另一个主机,消息在传递过程中被分割成小包。但是IP协议不能解决数据包在传输过程中遇到的问题,所以计算机需要TCP协议来保证传输的可靠性。
TCP叫端对端协议,当一台计算机要与另一台远程计算机进行通信时,TCP在两台计算机之间建立一个连接,用于发送和接收数据。TCP协议负责将数据包按一定顺序放好并发送,接收端在按照正确的顺序排列数据包。TCP提供了一个重发机制,当一个通信实体A发送消息给通信实体B后,A需要收到B的确认信息,如果没有收到B的确认信息,A会重新发送信息。
凡是在Internet上的计算机都必须安装IP协议和TCP协议,这两个协议统称TCP/IP协议。 TCP的三次握手
a.客户端向服务端发送一个请求 b.服务端收到请求后,回客户端一个响应 c.客户端向收到服务端的响应后,回服务端一个确认信息

1.1 ServerSocket创建服务端

ServerSocket用于监听来自客户端的Socket连接。如果没有连接,它将处于等待状态。 ServerSocket中常用方法:
Socket accept():如果接收到一个客户端Socket连接请求,该方法返回一个客户端对应的Socket对象。
ServerSocket(int port):用户指定端口port来创建一个ServerSocket,端口在1~65535之间。
close():用于关闭服务端。

public class Server {public static void main(String[] args) {// 1.实例化一个ServerSocket的对象ServerSocket serverSocket = null;OutputStream output = null;// 用于向别人发消息InputStream input = null;// 用于读取别人发过来的消息try {serverSocket = new ServerSocket(8888);System.out.println("等待服务端的连接...");// 2.监听,获取连接到的客户端 注意:在未连接成功之前,将一直处于阻塞状态Socket socket = serverSocket.accept();System.out.println("连接成功");// 3.获取网络到内存的一个输入流input = socket.getInputStream();// 4.读取数据,这个数据是Client发过来的byte[] arr = new byte[1024];int len = input.read(arr);String message = new String(arr, 0, len);// 5.组织信息String ipString = socket.getInetAddress().getHostAddress();int port = socket.getPort();System.out.println(ipString + ":" + port + "说:" + message);// 6.服务端给客户端回复消息output = socket.getOutputStream();output.write("你也好,好久不见了".getBytes());output.flush();} catch (IOException e) {e.printStackTrace();} finally {try {output.close();input.close();serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}
}

服务端不应该只接受一个客户端请求后就停止,所以在程序中可以通过循环不断的调用accept()方法:

while(true){
Socket socket=serverSocket.accept();
}

1.2 Socket创建客户端

客户端可以使用Socket构造器连接指定的服务端。

public class Client {public static void main(String[] args) {Socket socket = null;// 1.建立一个与服务端之间的连接OutputStream output = null;// 用于向别人发消息InputStream input = null;// 用于读取别人发过来的消息try {socket = new Socket("127.0.0.1", 8888);// 2.将需要发送的数据写入到网络中,注意:包含了两个流:InputStream和OutputStreamoutput = socket.getOutputStream();output.write("hello你好吗?".getBytes());// 3.写入output.flush();// 4.收取服务端发送来的消息 new BufferedInputStream(socket.getInputStream());input = socket.getInputStream();byte[] arr = new byte[1024];int len = input.read(arr);String message = new String(arr, 0, len);System.out.println("来自服务端的回复:" + message);} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {input.close();output.close();socket.close();} catch (IOException e) {e.printStackTrace();}}}
}

1.3 加入多线程

使用多线程实现客户端和服务端持续会话:

public class ServerThread extends Thread {private Socket client;public ServerThread() {}public ServerThread(Socket client) {this.client = client;}@Overridepublic void run() {OutputStream output = null;InputStream input = null;try {output = client.getOutputStream();input = client.getInputStream();// 从控制台进行获取数据Scanner scanner = new Scanner(System.in);// 进行循环的发送和接收消息while (true) {byte[] arr = new byte[1024];// 接收客户端发送来的消息int len = input.read(arr);String message = new String(arr, 0, len);System.out.println("来自客户端的消息:" + message);System.out.println("服务端对客户端说:");String reply = scanner.nextLine();// 回复消息output.write(reply.getBytes());output.flush();if (message.equals("886") || message.equals("bye") || message.equals("再见")) {// 约定break;}}} catch (IOException e) {e.printStackTrace();} finally {try {input.close();output.close();client.close();} catch (IOException e) {e.printStackTrace();}}}
}
public class Server {public static void main(String[] args) {ServerSocket serverSocket = null;try {serverSocket = new ServerSocket(8888);while (true) {Socket socket = serverSocket.accept();ServerThread thread = new ServerThread(socket);thread.start();		}} catch (IOException e) {e.printStackTrace();} finally {try {serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}
}
public class Client {public static void main(String[] args) {Socket socket = null;// 1.建立一个与服务端之间的连接OutputStream output = null;// 用于向别人发消息InputStream input = null;// 用于读取别人发过来的消息Scanner scanner = new Scanner(System.in);try {socket = new Socket("127.0.0.1", 8888);output = socket.getOutputStream();input = socket.getInputStream();while (true) {System.out.println("客户端对服务端说:");String message = scanner.nextLine();output.write(message.getBytes());// 进行发送output.flush();byte[] arr = new byte[1024];// 接收消息int len = input.read(arr);String reply = new String(arr, 0, len);System.out.println("收到服务端的反馈:" + reply);if (reply.equals("886") || reply.equals("bye") || reply.equals("再见")) {// 约定break;}}} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {input.close();output.close();socket.close();} catch (IOException e) {e.printStackTrace();}}}
}

2. 基于UDP的编程

UDP是User Datagram
Protocol的简称,用户数据报协议,它不管对方是否在线,直接向对方发送数据,至于对方能否收到,UDP无法控制,所以它是一种简单不可靠的协议。适用于一次传输量较少,对可靠性要求不高的情景。

特点:
a.不安全
b.无连接
c.效率高
d.UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内

public class Receiver {public static void main(String[] args) {// 1.实例化DatagramSocket的对象,需要进行绑定端口号:由发送方发送来的端口号进行决定DatagramSocket socket = null;try {socket = new DatagramSocket(6666);// 2.将接收到的数据封装到数据报包中,用来接收长度为 length 的数据包。byte[] arr = new byte[4096];DatagramPacket packet = new DatagramPacket(arr, arr.length);System.out.println("等待接收数据~~~~~~~");// 3.接收数据// 注意:将数据从网络中读取出来socket.receive(packet);// 4.获取发送方的详细信息byte[] messages = packet.getData();String result = new String(messages, 0, packet.getLength());// 获取发送方的ip地址// 返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。InetAddress address = packet.getAddress();String ip = address.getHostAddress();// 获取消息是从发送发的哪个端口号发出来的int port = packet.getPort();System.out.println(ip + ":" + port + "说:" + result.trim());} catch (SocketException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {socket.close();}}
}
public class Sender {public static void main(String[] args) {// 端口号表示的是指定的接收方的端口号,而发送方的端口是由系统自动分配的sendMessage("127.0.0.1", 6666, "你好啊");}public static void sendMessage(String ip, int port, String message) {// 1.实例化DatagramSocket的对象, 注意:和流的使用类似,使用套接字完成之后需要关闭DatagramSocket socket = null;try {socket = new DatagramSocket();// 2.构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。DatagramPacket packet = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(ip),port);// 3.发送,将数据写入网络的过程,void send(DatagramPacket p) 从此套接字发送数据报包。socket.send(packet);} catch (SocketException e) {// 父类为IOExceptione.printStackTrace();} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {socket.close();}}
}

传输控制协议(TCP):TCP(传输控制协议)定义了两台计算机之间进行可靠的传输而交换的数据和确认信息的格式,以及计算机为了确保数据的正确到达而采取的措施。协议规定了TCP软件怎样识别给定计算机上的多个目的进程如何对分组重复这类差错进行恢复。协议还规定了两台计算机如何初始化一个TCP数据流传输以及如何结束这一传输。TCP最大的特点就是提供的是面向连接、可靠的字节流服务。
用户数据报协议(UDP):UDP(用户数据报协议)是一个简单的面向数据报的传输层协议。提供的是非面向连接的、不可靠的数据流传输。UDP不提供可靠性,也不提供报文到达确认、排序以及流量控制等功能。它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。因此报文可能会丢失、重复以及乱序等。但由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。