预备知识:
1. 源IP地址和目的IP地址
在IP数据包头部中,有两个IP地址,分别叫做源IP地址和目的IP地址。只能将数据发送到对方的机器上并不能区分是哪个程序。
2. 端口号
端口号(port)是传输层协议的内容
- 是一个32位的整数
- 用来表示一个进程,告诉操作系统,当前的这个数据要交给哪一个进程来处理
- IP+端口号,标识网络上的唯一一台机器上的唯一进程
- 一个端口号只能被一个进程占用
注意:一个进程可以绑定多个端口号,但是一个端口号不能被多个进程绑定。
3. TCP协议(传输控制协议)
- 传输层协议
- 有连接(面向连接)
- 可靠传输
- 面向字节流
4. UDP协议(用户数据报协议)
- 传输层协议
- 无连接
- 不可靠传输
- 面向数据报
5.socket编程接口
- DatagramSocket类的常用方法:
1.DatagramSocket(int port,InetAddress laddr)
创建一个数据报套接字,绑定到指定的本地地址
2.DatagrsmSocket(SocketAddress bindaddr)
创建一个数据报套接字,绑定到指定的本地套接字地址
3.void bind(SocketAddress addr)
将此DatagramSocket绑定到待定的地址和端口
4.void connect(InetAddress address,int port)
将套接字连接到此套接字的远程地址
5.void receive(DatagramPacket p)
从此套接字接收数据包
6.void close()
关闭此数据报套接字
7.void send(DatagramPacket p)
从此套接字发送数据报包
- 对Socket的简单理解:内核和用户程序直接进行网络数据交互的接口。绑定了一组五元组。
基于udp协议实现客户端和服务器的代码演示
服务器
package udp.echo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class Server1226 {
public static void main(String[] args) throws IOException {
//1.新建一个DatagramSocket
DatagramSocket udpServerSocket=new DatagramSocket(9898);
byte[] receiveBuffer=new byte[1024];
DatagramPacket receivePacket=new DatagramPacket(receiveBuffer,receiveBuffer.length);
//2.等着客户端来撩
udpServerSocket.receive(receivePacket);
InetAddress clientAddress= receivePacket.getAddress();
System.out.printf("我从%s:%d 收到了消息%n",clientAddress.getHostAddress(),receivePacket.getPort());
System.out.printf("我一共收到了%d字节的数据%n",receivePacket.getLength());
//字节转字符
String message=new String (receivePacket.getData(),
0,
receivePacket.getLength(),
"UTF-8");
System.out.println(message);
udpServerSocket.close();
}
}
客户端
package udp.echo;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class Client1226 {
public static void main(String[] args) throws IOException {
DatagramSocket udpClientSocket=new DatagramSocket();
String message="收到我的消息没?";
byte[] senBuffer=message.getBytes("UTF-8");
byte[] serverIP=new byte[4];
serverIP[0]=127;
serverIP[1]=0;
serverIP[2]=0;
serverIP[3]=1;
InetAddress serverAddress=InetAddress.getByAddress(serverIP);
DatagramPacket sendPacket=new DatagramPacket(senBuffer,senBuffer.length,serverAddress,9898);
udpClientSocket.send(sendPacket);
udpClientSocket.close();
}
}
运行结果
基于tcp协议实现客户端和服务器的代码演示
服务器
package tcp.http;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class Server1226 {
public static void main(String[] args) throws IOException {
//监听8080端口
ServerSocket tcpServerSocket=new ServerSocket(8080);
while(true){
Socket clientSocket=tcpServerSocket.accept();
InetAddress clientAddress= clientSocket.getInetAddress();
int clientPort=clientSocket.getPort();
System.out.printf("有客户端连接上来 %s:%d%n",clientAddress.getHostAddress(),clientPort);
//获取字节流
InputStream is= clientSocket.getInputStream();
//字节流转换为字符流
InputStreamReader isReader=new InputStreamReader(is,"UTF-8");
//字符流转换为缓冲字符流
BufferedReader reader=new BufferedReader(isReader);
//获取输出字节流
OutputStream os=clientSocket.getOutputStream();
PrintStream out=new PrintStream(os,true,"UTF-8");
String line;
while((line=reader.readLine())!=null) {
System.out.println(line);
out.println("我已经收到了你的消息");
}
}
}
}
服务端运行结果
客户端
package tcp.http;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.*;
public class Client1226 {
public static void main(String[] args) throws IOException {
Socket tcpClientSocket=new Socket();
byte[] ipv4={127,0,0,1};
InetAddress serverAddress=InetAddress.getByAddress(ipv4);
SocketAddress serverSocketAddress= new InetSocketAddress(serverAddress,8080);
tcpClientSocket.connect(serverSocketAddress);
//通过字节流直接写入请求
OutputStream os=tcpClientSocket.getOutputStream();
os.write("我是好人\r\n".getBytes("UTF-8"));
//通过字节流,直接读取数据
InputStream is=tcpClientSocket.getInputStream();
byte[] buffer=new byte[1024];
int len=is.read(buffer);
String response=new String (buffer,0,len,"UTF-8");
System.out.println(response);
tcpClientSocket.close();
}
}
客户端运行结果
总结
- UDP是面向报文的,例如发送端发送的是"hello world",接收端接收到的一定是"hello world".
- TCP是面向流的,发送端可能不是一次发送完成,接收端读到\r\n才认为读取完毕。例如发送端发送的是"hello world",接收端可能接收的是"h",“ello”,“wor”,“ld”.
- TCP是面向连接的,用 connect连接
UDP是无连接的,没有调用过connect - UDP是不可靠的,发送后对方是否收到,不知道
TCP是可靠的,发送后对方一定是能收到的,如果收不到,也知道出了问题。