网络编程
-
TCP
长链接,可靠通信,字节流,效率比较低。
-
UDP
不是长链接,不可靠通信,数据报文,效率比较高。
-
端口port
为了区分同一台服务器上不同的网络通信的软件.
例如:IP地址相当于是一栋楼的门牌号,port就相当于是这栋楼里面的房间号码;
操作系统也会用到一些端口号,操作系统会保留1024以下的端口号,所以自己写程序时尽量避开操作系统保留的端口号;另外常用的端口也要避开,比如:tomcat服务器 8080,数据库mysql 3306,oracle 1521,如果你的软件跟别的软件用到了同样的端口,两个软件都启动时就会发生端口被占用的错误。
InetAddress 类
用来表示网络上的一台服务器,网络通信中数据的来源或目的地,相当于文件读写里的File类。
- InetAddress.getByName(“www.baidu.com”) 获取服务器地址对象;
- getHostAddress() 返回IP地址;
- getHostName() 返回域名或机器名(不一定能返回)。
package com.hqyj;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressDemo {
public static void main(String[] args) {
//本机地址:localhost
// 127.0.0.1
try {
InetAddress inetAddress = InetAddress.getLocalHost();
//System.out.println(new String(inetAddress.getAddress()));
System.out.println(inetAddress.getHostAddress());//返回本机ip地址
System.out.println(inetAddress.getHostName());//返回本机机名
//InetAddress baidu = InetAddress.getByName("www.baidu.com");//14.215.177.38
InetAddress baidu = InetAddress.getByName("14.215.177.38");//14.215.177.38
System.out.println(baidu.getHostAddress());
System.out.println(baidu.getHostName());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
ServerSocket 类
TCP通信(Socket 套接字)的服务端,被动的等待客户端发送信息,才能接收信息。
- 创建一个ServerSocket(服务端套接字);
- 调用accept方法等待客户端发送消息,阻塞进程(程序会等待);
- 通过accept方法返回的socket得到输入流;
- 读取输入流的内容(客户端发送的信息)。
package com.hqyj;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerSocketDemo {
public static void main(String[] args) {
InputStream inputStream = null;
Socket socket = null;
ServerSocket serverSocket = null;
try {
//创建网络对象
InetAddress inteAddress = InetAddress.getByName("192.168.3.1");
//创建一个Socket的服务对象,第一个参数是端口,第二个参数是最大连接数,第三个对象是网络地址
serverSocket = new ServerSocket(9090, 20, inteAddress);
//等待客户端发送信息,程序被阻塞
socket = serverSocket.accept();
//得到消息流
inputStream = socket.getInputStream();
byte[] bytes = new byte[1020];
//读取消息内容
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要和端口地址一样;
- 得到输出流;
- 往输出流写信息。
package com.hqyj;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class SocketDemo {
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
try {
socket = new Socket("192.168.3.1", 9090);
os = socket.getOutputStream();
byte[] bytes = "您好!".getBytes();
os.write(bytes);
os.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (os != null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
练习:上传文件
- 服务器
- 创建
- 获取输入流;
- 循环读取信息,读出的信息写到文件
package com.hqyj;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class UploadServer {
public static void main(String[] args) throws IOException {
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
//创建一个ServerSocket
ServerSocket serverSocket = new ServerSocket(9999, 10, inetAddress);
//接收输入
Socket socket = serverSocket.accept();
//获取输入流
InputStream is = socket.getInputStream();
//创建文件对象,用于保存上传的文件
FileOutputStream fos = new FileOutputStream("E:/new.png");
//循环读取信息,并写入文件
byte[] bytes = new byte[1024 * 32];
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("接收文件成功!");
}
}
- 客服端
- 连接服务器;
- 获得输出流;
- 读文件,把文件内容写入网络输出流。
package com.hqyj;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class UploadClient {
public static void main(String[] args) throws IOException {
//创建客户端,连接服务器
Socket socket = new Socket("127.0.0.1", 9999);
//打开输出流
OutputStream os = socket.getOutputStream();
//读取待上传的文件
FileInputStream fis = new FileInputStream("C:\\Users\\M\\Pictures\\QQ截图20201014235909.png");
byte[] bytes = new byte[1024 * 32];
int count = fis.read(bytes);
while (count != -1){
os.write(bytes, 0, count);
count = fis.read(bytes);
}
os.flush();
os.close();
socket.close();
fis.close();
System.out.println("上传文件成功!");
}
}
UDP
- DatagramSocket 创建UDB连接;
- DatagramPacket 报文内容。
服务端:
package com.hqyj;
import java.io.IOException;
import java.net.*;
public class UdpServer {
public static void main(String[] args) throws IOException {
//创建Socket
DatagramSocket socket = new DatagramSocket(8090, InetAddress.getByName("127.0.0.1"));
//创建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));
}
}
}
客户端:
package com.hqyj;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;
public class UdpClient {
public static void main(String[] args) throws IOException {
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("127.0.0.1"), 8090);
//发送报文包
socket.send(packet);
}
}
}
复习集合
- 泛型只能是引用类型,不能是基本类型;
- List的remove(Object obj),删除第一个匹配的元素。
- String的方法都是返回结果受影响,并不影响原字符串,方法执行的时候是新建一个对象来执行,并不会改变原字符串。
- toLowerCase()
- cancat()
- replace()
- subString()
- trim() 去掉空格返回字符串
练习
-
有两个数组{“四川”, “云南”, “贵州”},{“成都”, “昆明”, “贵阳”}
把省名(key)及它的省会(value)放进map
import java.util.HashMap; import java.util.Map; import java.util.Set; public class Association { public static void main(String[] args) { HashMap<String, String> map = new HashMap<>(); String[] strings = {"四川", "云南", "贵州"}; String[] strings1 = {"成都", "昆明", "贵阳"}; for (int i = 0; i < strings.length; i++) { map.put(strings[i], strings1[i]); } Set<Map.Entry<String, String>> entrys = map.entrySet(); for (Map.Entry<String, String> entry : entrys) { System.out.println(entry.getKey() + "\t-->\t" + entry.getValue()); } } }
-
有一个列表[“abcdab”, “aaaa”, “cdef”, “abcde”, “faabc”],计算并打印每个字母在列表中出现的次数并打印。
提示:遍历List,再遍历每个字符串(split(“”) 拆分字符串为数组)
每个字符存在map里,字符座位key,数量座位value
import java.util.*;
public class Duplicates {
public static void main(String[] args) {
List<String> list = Arrays.asList("abcdab", "aaaa", "cdef", "abcde", "faabc");
HashMap<String, Integer> map = new HashMap<>();
for (String str : list) {
String[] strs = str.split("");
for (String c : strs) {
if (map.containsKey(c)){
map.put(c, map.get(c) + 1);
}else{
map.put(c, 1);
}
}
/*for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
//String c = str.substring(i, i + 1);
}*/
}
//System.out.println(map);
Set<Map.Entry<String, Integer>> entrys = map.entrySet();
for (Map.Entry<String, Integer> entry : entrys) {
System.out.println(entry.getKey() + "\t-->\t" + entry.getValue());
}
}
}