TCP、UDP数据传输
-
TCP
长连接,可靠通讯,字节流的方式传输,效率低
-
UDP (用户数据报协议)
不是长连接,不可靠通讯有可能丢失,以数据报文方式传输,效率高
-
端口 port
为了区分同一台服务器上不同的通讯软件,比如qq用端口808,微信用端口909
例如:IP地址相当于一栋楼的门牌号,port相当于这栋楼里面的房间号码
操作也会用到一些端口号,操作系统保留1024以下的端口号,自己写程序尽量避开操作系统保留端口号,另外常用的端口也要避开,比如:tomcat 服务器8080, 数据库 mysql 3306、oracle 1521,如果你的软件跟别的软件用到了同样的端口,两个软件都启动时就会发生端口被占用的错误
InetAdress类
用来表示网络上的一台服务器,网络通信中数据的来源或目的地,相当于文件读写里F类
-
InetAddress.getByName(“www.baidu.com”);获取服务器对象
-
getHostAddress();返回IP地址
-
getHostName();返回域名或机器名(不一定能返回)
//本机的地址:localhost
//本机的地址:127.0.0.1
try {
InetAddress inetAddress = InetAddress.getLocalHost();
System.out.println(new String(inetAddress.getAddress()));
System.out.println(inetAddress.getHostAddress());
System.out.println(inetAddress.getHostName());
System.out.println("====baidu.com======");
// InetAddress baidu = InetAddress.getByName("www.baidu.com");
InetAddress baidu = InetAddress.getByName("14.215.177.39");
System.out.println(baidu.getHostAddress());
System.out.println(baidu.getHostName());
} catch (UnknownHostException e) {
e.printStackTrace();
}
ServerSocket类
TCP通信的服务端(Socket 套字节)的服务端,被动等待客户端发送信息,它就接收信息
-
创建SeverSocket(服务端套字节)
-
调用accept方法等待客户发送消息,阻塞进程(程序会等待)
-
通过accept方法返回的sockect得到输入流
-
读取输入流的内容(客户端发送的信息
InputStream inputStream = null; ServerSocket serverSocket = null; Socket socket = null; try { //创建网络地址对象 InetAddress inetAddress = InetAddress.getByName("192.168.3.125"); //创建一个Socket的服务对象,第一个参数是端口,第二个参数是最大连接数,第三个参数是网络连接地址 serverSocket = new ServerSocket(1002,10,inetAddress); //等待客户端返回消息,程序被阻塞 socket = serverSocket.accept(); //得到消息流 inputStream = socket.getInputStream(); byte[] bytes = new byte[10240]; //读取消息内容 int count = inputStream.read(bytes); System.out.println(new String(bytes)); } catch (IOException e) { e.printStackTrace(); }finally { if (inputStream != null){ try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if(serverSocket != null){ try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }
Socket 类
套字节的客户端,去连接客户端,连接上之后发送消息
- 创建客户端套接字Socket(端口号和IP地址跟服务区一致)
- 得到输出流
- 往输出流写信息
Socket socket = null;
OutputStream outputStream = null;
Scanner scanner = new Scanner(System.in);
try {
socket = new Socket("192.168.3.125",1002);
outputStream = socket.getOutputStream();
System.out.println("输入消息:");
String next = scanner.next();
byte[] bytes = next.getBytes();
outputStream.write(bytes);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
练习:上传文件
-
服务器
- 创建ServerSocket
- 获得输入流
- 循环读取信息,读出的信息写到文件
public class UploadSever { public static void main(String[] args) throws Exception { InetAddress inetAddress = InetAddress.getByName("127.0.0.1"); //创建serverSocket ServerSocket serverSocket = new ServerSocket(1009,10,inetAddress); //接收输入 Socket socket = serverSocket.accept(); //获取输入流 InputStream is = socket.getInputStream(); //创建一个对象用于保存上传的文件 FileOutputStream fos = new FileOutputStream("d:\\new.png"); //循环读取信息,并写入信息 byte[] bytes = new byte[1024*30]; int count = is.read(bytes);//读取上传的文件信息 while(count != -1){ fos.write(bytes,0,count);//写进文件 count = is.read(bytes);//读上传的文件 } fos.flush(); fos.close(); is.close(); socket.close(); serverSocket.close(); System.out.println("上传文件成功"); } }
-
客户端
- 连接服务器
- 获得输出流
- 读文件,把文件内容往网络输出流写
/** * TCP上传文件 * 客户端程序 */ public class UploadClient { public static void main(String[] args) throws Exception { Socket socket = new Socket("127.0.0.1",1009); OutputStream os = socket.getOutputStream(); FileInputStream fis = new FileInputStream("E:"); byte[] bytes = new byte[1024 * 30]; int count = fis.read(bytes); while (count != 0){ os.write(bytes,0,count); count = fis.read(bytes); } os.flush(); os.close(); socket.close(); fis.close(); System.out.println("上传成功!"); } }
UDP
-
DatagramSocket 创建UDP连接
-
DatagramPacket 报文内容
-
服务端
//创建Socket
DatagramSocket socket = new DatagramSocket(8888, InetAddress.getByName("192.168.3.178"));
//创建packet对象
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
while (true){
//读取数据
socket.receive(packet);
//返回读取到的字节数
int length = packet.getLength();
//new String(bytes, 0, length) 只打印有内容的字节,避免打出空白内容
System.out.println(new String(bytes, 0, length));
}
- 客户端
//创建socket
DatagramSocket socket = new DatagramSocket();
//控制台输入内容,完成发送
Scanner scanner = new Scanner(System.in);
while (true){
System.out.println("请输入要发送的消息:");
String msg = scanner.next();
byte[] bytes = msg.getBytes();
//创建报文包,参数依次为:字节数组, 长度,服务器地址, 服务器端口
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.3.178"), 8888);
//发送报文包
socket.send(packet);
}