网络编程
1.网络编程概述
计算机网络
- 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
网络编程
- 就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。
2.网络编程三要素
2.1.IP概述
-
每个设备在网络中的唯一标识
-
每台网络终端在网络中都有一个独立的地址,我们在网络中传输数据就是使用这个地址。
-
ipconfig:查看本机IP192.168.12.42
-
ping:测试连接192.168.40.62
-
本地回路地址:127.0.0.1
广播地址:255.255.255.255 -
IPv4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已经用尽。
-
IPv6:8组,每组4个16进制数。
-
1a2b:0000:aaaa:0000:0000:0000:aabb:1f2f
2.2.端口号概述
- 每个程序在设备上的唯一标识
- 每个网络程序都需要绑定一个端口号,传输数据的时候除了确定发到哪台机器上,还要明确发到哪个程序。
- 端口号范围从0-65535
- 编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了。
- 常用端口
mysql: 3306
oracle: 1521
web: 80
tomcat: 8080
QQ: 4000
feiQ: 2425
2.3.协议
- 为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
- UDP
面向无连接,数据不安全,速度快。不区分客户端与服务端。 - TCP
面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。 - 三次握手: 客户端先向服务端发起请求, 服务端响应请求, 传输数据
3.Socket通信原理
- A:Socket套接字概述:
* 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
* 通信的两端都有Socket。
* 网络通信其实就是Socket间的通信。
* 数据在两个Socket间通过IO流传输。
* Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port。
4.UDP传输
接收方获取ip和端口号
String ip = packet.getAddress().getHostAddress();
int port = packet.getPort();
package heima_day26;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class Demo1_Send {
/**
* * 1.发送Send
* 创建DatagramSocket, 随机端口号
* 创建DatagramPacket, 指定数据, 长度, 地址, 端口
* 使用DatagramSocket发送DatagramPacket
* 关闭DatagramSocket
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
String str = "abcd";
DatagramSocket socket = new DatagramSocket();//创建Socket相当于创建码头
DatagramPacket packet = //创建Packet相当于集装箱
new DatagramPacket(str.getBytes(), str.getBytes().length,InetAddress.getByName("127.0.0.1"),6666);
socket.send(packet);//发货,将数据发出去
socket.close();//关闭码头
//IO流相当于船,通过码头传输货物
}
}
package heima_day26;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class Demo1_Receive {
/**
* * 2.接收Receive
* 创建DatagramSocket, 指定端口号
* 创建DatagramPacket, 指定数组, 长度
* 使用DatagramSocket接收DatagramPacket
* 关闭DatagramSocket
* 从DatagramPacket中获取数据
* @param args
* @throws IOException
* @throws IOException
*/
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(6666);//创建Socket相当于码头
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);//创建Packet相当于创建集装箱
socket.receive(packet);//接货,接收数据
byte[] arr = packet.getData();//获取数据
int len = packet.getLength();//获取有效字节数
System.out.println(new String(arr,0,len));
socket.close();
}
}
4.2.UDP传输优化
package heima_day26;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Demo2_Send {
/**
* * 1.发送Send
* 创建DatagramSocket, 随机端口号
* 创建DatagramPacket, 指定数据, 长度, 地址, 端口
* 使用DatagramSocket发送DatagramPacket
* 关闭DatagramSocket
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);//创建键盘录入对象
DatagramSocket socket = new DatagramSocket();//创建Socket相当于创建码头
while(true) {
String line = sc.nextLine();//获取键盘录入的字符串
if("quit".equals(line)) {
break;
}
DatagramPacket packet = //创建Packet相当于集装箱
new DatagramPacket(line.getBytes(), line.getBytes().length,InetAddress.getByName("127.0.0.1"),6666);
socket.send(packet);//发货,将数据发出去
}
socket.close();//关闭码头
//IO流相当于船,通过码头传输货物
}
}
package heima_day26;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class Demo2_Receive {
/**
* * 2.接收Receive
* 创建DatagramSocket, 指定端口号
* 创建DatagramPacket, 指定数组, 长度
* 使用DatagramSocket接收DatagramPacket
* 关闭DatagramSocket
* 从DatagramPacket中获取数据
* @param args
* @throws IOException
* @throws IOException
*/
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(6666);//创建Socket相当于码头
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);//创建Packet相当于创建集装箱
while(true) {
socket.receive(packet);//接货,接收数据
byte[] arr = packet.getData();//获取数据
int len = packet.getLength();//获取有效字节数
String ip = packet.getAddress().getHostAddress();//获取ip地址
int port = packet.getPort();//获取端口号
System.out.println(ip+":"+port+":"+new String(arr,0,len));
}
}
}
4.3.UDP传输多线程
package heima_day26;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class Demo3_MoreThread {
/*
* 发送和接收在一个窗口完成
*/
public static void main(String[] args) {
new Receive().start();
new Send().start();
}
}
class Receive extends Thread {
public void run() {
try {
DatagramSocket socket = new DatagramSocket(6666); //创建socket相当于创建码头
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); //创建packet相当于创建集装箱
while(true) {
socket.receive(packet); //接收货物
byte[] arr = packet.getData();
int len = packet.getLength();
String ip = packet.getAddress().getHostAddress();
System.out.println(ip + ":" + new String(arr,0,len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Send extends Thread {
public void run() {
try {
DatagramSocket socket = new DatagramSocket(); //创建socket相当于创建码头
Scanner sc = new Scanner(System.in);
while(true) {
String str = sc.nextLine();
if("quit".equals(str))
break;
DatagramPacket packet = //创建packet相当于创建集装箱
new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666);
socket.send(packet); //发货
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.4.GUIchat
package heima_day26;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.border.Border;
public class Demo4_GUIchat extends Frame{
private TextField tf;
private Button send;
private Button log;
private Button clear;
private Button shake;
private TextArea viewText;
private TextArea sendText;
private DatagramSocket socket;
private BufferedWriter bw;
/**
* GUI聊天
* @throws IOException
*
*/
public Demo4_GUIchat() throws IOException {
init();
southPanel();
centerPanel();
event();
}
public void event() {
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
try {
socket.close();
bw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
System.exit(0);
}
});
send.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
send();
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
log.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
logFile();
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
clear.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
viewText.setText("");//清屏
}
});
shake.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
send(new byte[] {-1},tf.getText());
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
sendText.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER) {
try {
send();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
});
}
private void shake() throws Exception {
int x = this.getLocation().x;//获取横坐标的位置
int y = this.getLocation().y;//获取纵坐标的位置
for(int i = 0; i < 10 ; i++) {
try {
this.setLocation(x + 20, y + 20);
Thread.sleep(100);
this.setLocation(x + 20, y - 20);
Thread.sleep(100);
this.setLocation(x - 20, y + 20);
Thread.sleep(100);
this.setLocation(x - 20 ,y - 20);
Thread.sleep(100);
this.setLocation(x, y);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void logFile() throws IOException {
bw.flush();//刷新缓冲区
FileInputStream fis = new FileInputStream("config.txt");
ByteArrayOutputStream baos = new ByteArrayOutputStream();//在内存中创建缓冲区
int len;
byte[] arr = new byte[8192];
while((len = fis.read(arr)) != -1) {
baos.write(arr,0,len);
}
String str = baos.toString();//将内存中的内容转换成了字符串
viewText.setText(str);
fis.close();
}
private void send(byte[ ]arr,String ip) throws IOException {
DatagramPacket packet = new
DatagramPacket(arr, arr.length,InetAddress.getByName(ip),9999);
socket.send(packet);//发送数据
}
private void send() throws IOException {
String message =sendText.getText();//获取发送区域的内容
String ip = tf.getText();//获取ip地址
ip = ip.trim().length() == 0 ? "255.255.255.255" : ip;
send(message.getBytes(),ip);
String time = getCurrentTime();
String str = time + " 我对:"+ip+"说\r\n"+message+"\r\n";//alt + shift + l 抽取局部变量
viewText.append(str);//将信息添加到显示区域
bw.write(str);//将信息写到数据库中
sendText.setText("");
}
private String getCurrentTime() {
Date d = new Date();//创建当前日期对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
return sdf.format(d);//将时间格式化
}
public void centerPanel() {
Panel center = new Panel(); //创建中间的Panel
viewText = new TextArea();
sendText = new TextArea(5,1);
center.setLayout(new BorderLayout());//设置为边界布局管理器
center.add(sendText,BorderLayout.SOUTH);//发送的文本区域放在南边
center.add(viewText,BorderLayout.CENTER);//显示的区域放在中间
viewText.setEditable(false);//设置不可以编辑
viewText.setBackground(Color.white);//设置背景颜色
sendText.setFont(new Font("xxx",Font.PLAIN,20));
viewText.setFont(new Font("xxx",Font.PLAIN,20));
this.add(center,BorderLayout.CENTER);
pack();//父类方法,从新检查一下界面,让没能显示的组件,都显示出来。
}
public void southPanel() {
Panel south = new Panel(); //创建南边的Panel
tf = new TextField(15);
tf.setText("127.0.0.1");
send = new Button("发 送");
log = new Button("记 录");
clear = new Button("清 屏");
shake = new Button("震 动");
south.add(tf);
south.add(send);
south.add(log);
south.add(clear);
south.add(shake);
this.add(south,BorderLayout.SOUTH);
}
private void init() throws IOException {
this.setLocation(500,50);
this.setSize(400,600);
new Receive().start();
socket = new DatagramSocket();
bw = new BufferedWriter(new FileWriter("config.txt",true));//需要尾部追加true
this.setVisible(true);
}
private class Receive extends Thread{//接收和发送需要同时执行,所以定义成多线程
public void run() {
try {
DatagramSocket socket = new DatagramSocket(9999);
DatagramPacket packet = new DatagramPacket(new byte[8192], 8192);
while(true) {
socket.receive(packet);//接收信息
byte[] arr = packet.getData();//读取字节数据
byte len = (byte) packet.getLength();//获取有效的字节数据
if(arr[0] == -1 && len == 1) {//如果发过来的数组第一个存储的值是-1,并且数组长度是1
shake();//调用震动方法
continue;//终止本次循环,继续下次循环,因为震动后不需要执行下面的代码
}
String message = new String(arr,0,len);//转换成字符串
String time =getCurrentTime();//获取当前时间
String ip = packet.getAddress().getHostAddress();//获取IP
String str = time+" "+ip+"对我说:\r\n"+message+"\r\n";
viewText.append(str);
bw.write(str);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
new Demo4_GUIchat();
}
}
5.TCP协议
1.客户端
- 创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器
- 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
- 输入流可以读取服务端输出流写出的数据
- 输出流可以写出数据到服务端的输入流
2.服务端
- 创建ServerSocket(需要指定端口号)
- 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
- 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
- 输入流可以读取客户端输出流写出的数据
- 输出流可以写出数据到客户端的输入流
package heima_day26;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Demo6_Cliert {
/**
* 1.客户端
* 创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器
* 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
* 输入流可以读取服务端输出流写出的数据
* 输出流可以写出数据到服务端的输入流
* @param args
* @throws Exception
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, Exception {
Socket socket = new Socket("127.0.0.1",12345);
InputStream is = socket.getInputStream();//获取客户端输入流
OutputStream os = socket.getOutputStream();//获取客户端输出流
byte[] arr = new byte[1024];
int len = is.read(arr);//读取服务端发过来的数据
System.out.println(new String(arr,0,len));//将数据转换成字符串并打印
os.write("abc".getBytes());//客户端向服务器写数据
socket.close();
}
}
package heima_day26;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Demo6_Server {
/**
* 2.服务端
* 创建ServerSocket(需要指定端口号)
* 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
* 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
* 输入流可以读取客户端输出流写出的数据
* 输出流可以写出数据到客户端的输入流
* @throws Exception
*
*/
public static void main(String[] args) throws Exception {
ServerSocket sever = new ServerSocket(12345);
Socket socket = sever.accept();//接受客户端的请求
InputStream is = socket.getInputStream();//获取客户端输入流
OutputStream os = socket.getOutputStream();//获取客户端输出流
os.write("百度一下你就知道".getBytes());//服务端向客户端写出数据
byte[] arr = new byte[1024];
int len = is.read(arr);//读取客户端发过来的数据
System.out.println(new String(arr,0,len));//将数据转换成字符串并打印
socket.close();
}
}
5.2.TCP协议代码优化
package heima_day26;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Demo7_Server {
//TCP协议代码优化
public static void main(String[] args) throws Exception {
//Demo1();
ServerSocket sever = new ServerSocket(12345);
while(true) {
final Socket socket = sever.accept();//接受客户端的请求
new Thread() {
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
PrintStream ps = null;
try {
ps = new PrintStream(socket.getOutputStream());
} catch (IOException e1) {
e1.printStackTrace();
}
ps.println("dcba");
try {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
private static void Demo1() throws IOException {
ServerSocket sever = new ServerSocket(12345);
Socket socket = sever.accept();//接受客户端的请求
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream ps = new PrintStream(socket.getOutputStream());//PrintSteam中有写出换行的方法
ps.println("dcba");
System.out.println(br.readLine());
socket.close();
}
}
package heima_day26;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Demo7_Cliert {
//TCP协议代码优化
public static void main(String[] args) throws Exception, IOException {
Socket socket = new Socket("127.0.0.1",12345);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream ps = new PrintStream(socket.getOutputStream());//PrintSteam中有写出换行的方法
System.out.println(br.readLine());
ps.println("abcd");
socket.close();
}
}