TCP的Java支持
协议相当于相互通信的程序间达成的一种约定,它规定了分组报文的结构、交换方式、包含的意义以及怎样对报文所包含的信息进行解析,TCP/IP协议族有IP协议、TCP协议和UDP协议。现在TCP/IP协议族中的主要socket类型为流套接字(使用TCP协议)和数据报套接字(使用UDP协议)。
TCP协议提供面向连接的服务,通过它建立的是可靠地连接。Java为TCP协议提供了两个类:Socket类和ServerSocket类。一个Socket实例代表了TCP连接的一个客户端,而一个ServerSocket实例代表了TCP连接的一个服务器端,一般在TCP Socket编程中,客户端有多个,而服务器端只有一个,客户端TCP向服务器端TCP发送连接请求,服务器端的ServerSocket实例则监听来自客户端的TCP连接请求,并为每个请求创建新的Socket实例,由于服务端在调用accept()等待客户端的连接请求时会阻塞,直到收到客户端发送的连接请求才会继续往下执行代码,因此要为每个Socket连接开启一个线程。服务器端要同时处理ServerSocket实例和Socket实例,而客户端只需要使用Socket实例。另外,每个Socket实例会关联一个InputStream和OutputStream对象,我们通过将字节写入套接字的OutputStream来发送数据,并通过从InputStream来接收数据。
TCP连接的建立步骤
客户端向服务器端发送连接请求后,就被动地等待服务器的响应。典型的TCP客户端要经过下面三步操作:
1、创建一个Socket实例:构造函数向指定的远程主机和端口建立一个TCP连接;
2.通过套接字的I/O流与服务端通信;
3、使用Socket类的close方法关闭连接。
服务端的工作是建立一个通信终端,并被动地等待客户端的连接。典型的TCP服务端执行如下两步操作:
1、创建一个ServerSocket实例并指定本地端口,用来监听客户端在该端口发送的TCP连接请求;
2、重复执行:
1)调用ServerSocket的accept()方法以获取客户端连接,并通过其返回值创建一个Socket实例;
2)为返回的Socket实例开启新的线程,并使用返回的Socket实例的I/O流与客户端通信;
3)通信完成后,使用Socket类的close()方法关闭该客户端的套接字连接。
DEMO
客户端
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.Inet4Address;
- import java.net.Inet6Address;
- import java.net.InetAddress;
- import java.net.NetworkInterface;
- import java.net.Socket;
- import java.net.SocketException;
- import java.net.UnknownHostException;
- import java.util.Enumeration;
-
- public class Exercise {
- public void tcpExample(){
- try {
- Socket socket = new Socket("192.168.138.46",8344);
- System.out.println("Connection ....to server sending echo string");
- OutputStream out = socket.getOutputStream();
- System.out.println("发送数据……");
- out.write("测试连接并发送数据到服务器成功……".getBytes());
- socket.close();
- System.out.println("客户端已经关闭");
-
- } catch (UnknownHostException e) {
-
- e.printStackTrace();
- } catch (IOException e) {
-
- e.printStackTrace();
- }
-
-
- }
- public static void main(String[] args) {
- Exercise e = new Exercise();
-
- e.tcpExample();
-
- }
- }
服务端
- package NET;
-
- import java.io.IOException;
- import java.io.InputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.net.SocketAddress;
-
- public class TCPServer {
- //设置缓冲区的大小
- private static final int BUFSIZE = 50;
-
- public static void tcpsever(){
- try {
- ServerSocket serSocket = new ServerSocket(8344);
- int recvMsgSize = 0;
- int total=0;
- byte[] receive = new byte[BUFSIZE];
- while(true){
- //此方法返回一个服务器的关联socket,用此进行数据交换
- Socket clntSock = serSocket.accept();
- SocketAddress socadd = clntSock.getRemoteSocketAddress();
- System.out.println("clint address:"+socadd);
- InputStream in = clntSock.getInputStream();
- while((total=in.read(receive, recvMsgSize, BUFSIZE-recvMsgSize))!=-1){
- recvMsgSize += total;
- }
- System.out.println("从客户端收到的数据:"+new String(receive));
- clntSock.close();
- System.out.println("关闭和此客户端的连接……");
- }
-
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- }
- public static void main(String args[]){
- tcpsever();
- }
-
- }


UDP的Java支持
UDP协议提供的服务不同于TCP协议的端到端服务,它是面向非连接的,属不可靠协议,UDP套接字在使用前不需要进行连接。实际上,UDP协议只实现了两个功能:
1)在IP协议的基础上添加了端口;
2)对传输过程中可能产生的数据错误进行了检测,并抛弃已经损坏的数据。
Java通过DatagramPacket类和DatagramSocket类来使用UDP套接字,客户端和服务器端都通过DatagramSocket的send()方法和receive()方法来发送和接收数据,用DatagramPacket来包装需要发送或者接收到的数据。发送信息时,Java创建一个包含待发送信息的DatagramPacket实例,并将其作为参数传递给DatagramSocket实例的send()方法;接收信息时,Java程序首先创建一个DatagramPacket实例,该实例预先分配了一些空间,并将接收到的信息存放在该空间中,然后把该实例作为参数传递给DatagramSocket实例的receive()方法。在创建DatagramPacket实例时,要注意:如果该实例用来包装待接收的数据,则不指定数据来源的远程主机和端口,只需指定一个缓存数据的byte数组即可(在调用receive()方法接收到数据后,源地址和端口等信息会自动包含在DatagramPacket实例中),而如果该实例用来包装待发送的数据,则要指定要发送到的目的主机和端口。
UDP的通信建立的步骤
UDP客户端首先向被动等待联系的服务器发送一个数据报文。一个典型的UDP客户端要经过下面三步操作:
1、创建一个DatagramSocket实例,可以有选择地对本地地址和端口号进行设置,如果设置了端口号,则客户端会在该端口号上监听从服务器端发送来的数据;
2、使用DatagramSocket实例的send()和receive()方法来发送和接收DatagramPacket实例,进行通信;
3、通信完成后,调用DatagramSocket实例的close()方法来关闭该套接字。
由于UDP是无连接的,因此UDP服务端不需要等待客户端的请求以建立连接。另外,UDP服务器为所有通信使用同一套接字,这点与TCP服务器不同,TCP服务器则为每个成功返回的accept()方法创建一个新的套接字。一个典型的UDP服务端要经过下面三步操作:
1、创建一个DatagramSocket实例,指定本地端口号,并可以有选择地指定本地地址,此时,服务器已经准备好从任何客户端接收数据报文;
2、使用DatagramSocket实例的receive()方法接收一个DatagramPacket实例,当receive()方法返回时,数据报文就包含了客户端的地址,这样就知道了回复信息应该发送到什么地方;
3、使用DatagramSocket实例的send()方法向服务器端返回DatagramPacket实例。
UDP Socket Demo
这里有一点需要注意:
UDP程序在receive()方法处阻塞,直到收到一个数据报文或等待超时。由于UDP协议是不可靠协议,如果数据报在传输过程中发生丢失,那么程序将会一直阻塞在receive()方法处,这样客户端将永远都接收不到服务器端发送回来的数据,但是又没有任何提示。为了避免这个问题,我们在客户端使用DatagramSocket类的setSoTimeout()方法来制定receive()方法的最长阻塞时间,并指定重发数据报的次数,如果每次阻塞都超时,并且重发次数达到了设置的上限,则关闭客户端。
DEMO‘
- package NET;
-
- import java.io.IOException;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.Inet4Address;
- import java.net.InetAddress;
- import java.net.Socket;
- import java.net.SocketException;
- import java.net.UnknownHostException;
-
- import com.sun.jmx.snmp.InetAddressAcl;
-
- public class UDP {
- private final static int TIMEOUT = 3000;
- private final static int BUFSIZE = 50;
- private final static int tries = 5;
-
-
-
-
-
- public void udpclnt() throws SocketException, UnknownHostException{
- int tril = 0;
- DatagramSocket socket = new DatagramSocket();
- String art = "UDP连接测试成功……";
- byte[] by = art.getBytes();
- InetAddress address = null; <li class="alt" style="border-top: none; border-right: none; border-bottom: none; border-left: 3px solid rgb(108, 226, 108); border-image: initial; list-style-type: decimal-leading-zero; list-style-image: initial; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !impo