TCP
1. 客户端代码
public class TCPEchoClient {
public static void main(String args[]) throws IOException {
byte[] data = "123456".getBytes();//获取字节数组
Socket socket = new Socket("127.0.0.1",8080);//对于客户端来说,需要对服务端发起请求,绑定IP和端口
InputStream in = socket.getInputStream();//输入流
OutputStream out = socket.getOutputStream();//输出流
out.write(data);//向服务端发送数据
int totalBytesRecd = 0;
int bytesRecd;
while(totalBytesRecd < data.length) {
if((bytesRecd = in.read(data, totalBytesRecd,
data.length-totalBytesRecd))==-1) {//读取服务端发送字节流
throw new SocketException("Connection close prematurely");
}
totalBytesRecd+=bytesRecd;
}
System.out.println("Recd"+new String(data)+totalBytesRecd);
socket.close();
}
}
2. 服务端代码
public class TCPEchoServer {
public static final int BUFSIZE = 32;
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8080);//服务端通过固定的端口提供服务,客户端的ip和地址都可以变化,但是服务端需要绑定Ip和服务。
int recvMsgSize;
byte[] recvbuf = new byte[BUFSIZE];
while(true) {
Socket cliSocket = server.accept();//监听客户端请求,建立起连接
SocketAddress clientAddress = cliSocket.getRemoteSocketAddress();
System.out.println("handling client at"+clientAddress);//输出客户端地址
InputStream inputStream = cliSocket.getInputStream();
OutputStream outputStream = cliSocket.getOutputStream();
while((recvMsgSize = inputStream.read(recvbuf)) != -1) {
outputStream.write(recvbuf, 0 , recvMsgSize);//将受到的字节,写出输出流
}
cliSocket.close();
}
}
}
3. 解析
-
通过简单的Java Socket编程,我们可以可以跟TCP的三次握手结合来看。
image.png
三次握手的过程中,客户端是作为主动请求方,而服务端的特定服务有确定的Ip和端口,这样每次。比如说80对应HTTP,21对应FTP等等。客户端需要通过一个Socket类表示TCP的一端,里面的参数表明所要连接到的服务端的IP的地址。客户端可以有多个,并且分配的端口是随机的。
- inputStream,outputStream则是输入流和输出流,Socket的读取和写入,跟文件的读写差不多。但是Socket是要通过网络的
- 在服务端这边,先是绑定端口,ip就是它的主机地址。它需要有一个ServerSocket来监听客户端请求,也就是用来三次握手建立连接的。当建立起连接之后,需要
Socket cliSocket = server.accept()来处理连接的任务。所以客户端只需要一个Socket,而服务端需要ServerSocket和Socket。为每一个请求分配一个Socket - read()函数为-1发生在客户端或者服务端提前关闭连接的时候
UDP
1. 客户端
public class UDPEchoClient {
public static final int TIMEOUT = 3000;//超时时间,防止UDP一直阻塞在等待读中,如果一直没有响应,就会发送失败
public static final int MAXTRIES = 5;//由于数据报文可能丢失,我们必须准备好重新
//传输数据。本例中,我们最多循环5次,来发送数
// 据报文并尝试接收响应信息。
public static void main(String [] args) throws IOException {
InetAddress serverAddress = InetAddress.getLocalHost();
byte[] byteToSend = "123456".getBytes();
int servePort = 7;
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(TIMEOUT);
DatagramPacket sendPacket = new DatagramPacket(byteToSend,
byteToSend.length, serverAddress, servePort );//发送的报文
DatagramPacket receivePacket = new DatagramPacket(new byte[byteToSend.length],
byteToSend.length);//接收报文
int tries = 0;
boolean receiveResponse = false;
do{
socket.send(sendPacket);
try {
socket.receive(receivePacket);
if (!receivePacket.getAddress().equals(serverAddress)) {
throw new IOException("Received form an unknown source");
}
receiveResponse = true;
}catch (InterruptedIOException e) {
tries +=1;
System.out.println("Time out");
}
} while ((!receiveResponse) && (tries < MAXTRIES));
if(receiveResponse) {
System.out.println("Received"+ new String(receivePacket.getData()));
} else {
System.out.println("No Response, give up");
}
socket.close();
}
- 服务端
public class UDPEchoServer {
private static final int ECHOMAX = 255;
public static void main(String [] args) throws IOException {
int servePort = 7;
DatagramSocket socket = new DatagramSocket(servePort);
DatagramPacket packet = new DatagramPacket(new byte[ECHOMAX], ECHOMAX);
while(true) {
socket.receive(packet);//接受报文
System.out.println("Handling client at "+packet.getAddress().getHostAddress()
+"on port" +packet.getPort());
socket.send(packet);//复制并返回客户端
packet.setLength(ECHOMAX);//最大长度255
}
}
}
3. 解析
- UDP与TCP的本质区别就是UDP是面向无连接的,它不需要三次握手,就可以发送报文,在IP的基础上进行数据传输,不保证可靠性传输。所以,应用层需要做好响应的准备,对于数据丢失的相关处理。虽然UDP不可靠,但在很多场景上用处却很大,比如说QQ,DNS这种少量的数据传输。它的好处主要是效率和灵活性。不需要三次握手,所以效率也更高,灵活性是指如果除可靠的字节流服务外,还有其他需求,UDP协议则提供了一个最小开销的平台来满足任何需求的实现。
- UDP Socket主要是使用DatagramSocket和DatagramPacket,来通信,以及作为IO流。
- 接收者应该提供一个有足够大
的缓存空间的DatagramPacket实例,以完整地存
放调用receive()方法时应用程序协议所允许的最
大长度的消息。这个技术能够保证数据不会丢失。
一个DatagramPacket实例中所运行传输的最大数
据量为65 507字节,即UDP数据报文所能负载的
最多数据。因此,使用一个有65 600字节左右缓存
数组的数据包总是安全的。
网友评论