一 概述
1
网络应用程序由 网络编程、io流、多线程组成。
但是很多怕我们做不好,所以很多都封装起来了,我们做的最多的是造对象,调方法,造对象,调方法。
2网络编程三要素:
ip地址:
是网络中每台计算机的唯一标识
通过cmd中的 ipconfig可以查看本机的ip地址
端口号:
用来区分电脑上的每个应用程序
有效端口:0~65535,其中0~1024系统使用或保留端口
协议:(重点)
按照某种规则(TCP, UDP)
UDP: 数据打包,不连接
64k
不可靠
速度快
应用:QQ聊天、在线视频用的都是UDP传输协议
TCP: 建立连接
可以大数据量传输
可靠(三次握手)
速度慢
应用:FTP,File Transfer Protocol(文件传输协议)
二 UDP协议
1 发送
创建UDP发送端的Socket对象
创建数据并把数据打包
发送数据
释放资源
代码1: (InetAddress的使用)
public static void main(String[] args) {
InetAddress address = InetAddress.getByName("asd-PC");
String name = address.getName();
String ip = address.getAddress();
System.out.println(name + " " + ip);
}
代码2:
public static void main(String[] args) throws IOException{
DatagramSocket ds = new DatagramSocket();
byte[] bys = "hello, udp, 我来了".getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getByName("asd-PC"), 10086);
ds.send(dp);
ds.close();
}
2 接收
创建UDP接收端的Socket对象
创建数据包用于接收数据
接收数据
解析数据包
释放资源
代码3:
public static void main(String[] args) {
DatagramSocket ds = new DatagramSocket(10086);
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
ds.receive(dp);
// 解析数据包,并显示在控制台
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(), 0, dp.getLength())
System.out.println(ip + " : " + data);
ds.close();
}
3 案例
代码1: 键盘录入数据(自己控制录入结束) send
public static void main(String[] args) {
DatagramSocket ds = new DatagramSocket();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = br.readLine()) != null){
if("886".equals(line)){
break;
}
byte[] bys = line.getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getByName("asd-PC"), 10011);
ds.send(dp);
}
ds.close();
}
代码2:
public static void main(String[] args) {
DatagramSocket ds = new DatagramSocket(10011);
while(true){
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(), 0, dp.getLength());
System.out.println(ip + " " + data);
}
// 接收端应该一直开着等待接收数据,是不需要关闭
// ds.close();
}
代码3: 聊天室 刘意老师的05包中的
三 TCP协议
1 接收
TCP服务器端的Socket对象
监听客户端连接
获取输入流,读取数据
释放资源
代码1:
public static void main(String[] args) {
ServerSocket ss = new ServerSocket(12345);
Socket s = ss.accept();
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys);
String str = new String(bys, 0, len);
System.out.println( str);
String ip = s.getInetAddress().getHostAddress();
s.close();
ss.close();
}
2 发送
创建TCP客户端的Socket对象
获取输出流,写数据
释放资源
代码2:
public static void main(String[] args) {
Socket s = new Socket("192.168.1.101", 12345);
OutputStream os = s.getOutputStream();
os.write("hello, tcp, 我来了".getBytes());
s.close();
}
四 案例
案例一 客户端读取文本文件服务器写到文本文件
代码1: Server
public static void main(String[] args) {
ServerSocket ss = new ServerSocket(11114);
Socket s = ss.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter bw = new BufferedWriter(new FileWriter(""));
String line = null;
while((line = br.readLine()) != null){
bw.write(line);
bw.newLine();
bw.flush();
}
BufferedWriter bw2 = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bw2.write("okay");
bw2.newLine();
bw2.flush();
bw.close();
s.close();
}
代码2:Client
public static void main(String[] args) {
Socket s = new Socket("192.168.1.101", 11114);
BufferedReader br = new BufferedReader(new FileReader(""));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while((line = br.readLine()) != null){
bw.write(line);
bw.newLine();
bw.flush();
}
s.shutdownOutput();
BufferedReader br2 = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line2 = br2.readLine();
System.out.println(line2);
br.close();
s.close();
}
3 理解
1)Client端的s.shutdownOutput();可以通知Server端,传输结束了,要不然(line = br.readLine())是阻塞式语句,会一直等在那里,后面的反馈及其他语句永远没法执行。
(可以下载api看一下shutdownOutput()是怎么实现的)
2)由两端对io流的封装可以想到,客户端键盘录入服务器控制台输出、客户端键盘录入服务器写到文本文件、客户端读取文本文件服务器控制台输出等案例,仅仅是对流的封装对象变了而已
案例2 上传图片
按照案例1的逻辑完全可以做好(我自己就敲代码实现了。所有字符流的地方变成字节流即可)
案例3 多线程改进上传文件
代码1: Client 不变,和之前的一样也是可以的。
代码2: Server端 (感觉真漂亮! )
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(11111);
while (true) {
Socket s = ss.accept();
new Thread(new UserThread(s)).start();
}
}
代码3: 线程
public class UserThread implements Runnable {
private Socket s;
public UserThread(Socket s) {
this.s = s;
}
public void run() {
try {
// 封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
String newName = System.currentTimeMillis() + ".java";
BufferedWriter bw = new BufferedWriter(new FileWriter(newName));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
BufferedWriter bwServer = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush();
bw.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}