网络编程三要素:
1、IP地址:设备在网络中的地址,是唯一标识
1)DNS服务将域名转为IP,在进行访问
2)IPv4(点分十进制)、IPv6(冒分十六进制)
127.0.0.1:送回地址,也称本地回环地址 ,可以代表本机IP地址,一般用于测试。
2、端口:应用程序在设备中的唯一标识
端口号:用两个字节表示的整数,取值范围:065535,其中01023之间的端口用于一些知名网站服务或应用。我们用1024以上即可。一个端口只允许被一个应用程序使用
3、协议:数据在网络中传输的规则,常见的有UDP和TCP
UDP:单播,组播(地址:244.0.0.0239.255.255.255,其中244.0.0.0244.0.0.255为预留的组播地址),广播
单播
public class ClientDemo1 {
public static void main(String[] args) throws IOException {
//UDP发送数据
//1、创建发送端的 DatagramSocket对象,相当于码头
//2、创建数据,并且把数据打包(DatagramPacket),相当于包裹
//3、调用DatagramSocket对象的send方法发送数据,相当于码头发送包裹
//4、释放资源,相当于关闭码头
DatagramSocket ds = new DatagramSocket();//不指定端口,则随机发送
//DatagramPacket(byte[] buf, int length, InetAddress address, int port)
//构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号。
String s = "我爱你中国,亲爱的母亲";
byte[] bytes = s.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
ds.send(dp);
ds.close();
}
}
public class ServerDemo1 {
public static void main(String[] args) throws IOException {
//先运行接收端,再运行发送端,不然接收不到数据,如果没接收到数据,则会死等(阻塞)
//UDP接收数据
//1、创建接收端的 DatagramSocket对象,相当于对接码头
//2、创建空包裹,用于接收数据,相当于创建一个包裹,准备接收数据
//3、调用DatagramSocket对象的receive()方法接收数据,并把数据放入箱子
//4、解析数据包,并在控制台展示
//5、释放资源,关闭码头
DatagramSocket ds = new DatagramSocket(10000);//指定端口,,表示接收端从10000端口接收数据
//DatagramPacket(byte[] buf, int length)
//构造一个 DatagramPacket用于接收长度的数据包 length 。
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
System.out.println("----------接收前-------------");
ds.receive(dp);
System.out.println("----------接收后-------------");
byte[] data = dp.getData();//获取数据,其实直接用上面的bytes也行
int length = dp.getLength();
System.out.println(new String(data,0,length));
//System.out.println(new String(bytes,length));
ds.close();
}
}
组播
public class UdpClient1 {
public static void main(String[] args) throws IOException {
//UDP组播发送数据
//1、创建发送端的 DatagramSocket对象,相当于码头
//2、创建数据,并且把数据打包(DatagramPacket),相当于包裹
//3、调用DatagramSocket对象的send方法发送数据,相当于码头发送包裹。单播传IP,组播传组播地址
//4、释放资源,相当于关闭码头
DatagramSocket ds = new DatagramSocket();
String s = "hello,组播";
byte[] bytes = s.getBytes();
//与单播区别:单播传IP,组播传组播地址
InetAddress address = InetAddress.getByName("224.0.1.0");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
ds.send(dp);
ds.close();
}
}
public class UdpServer1 {
public static void main(String[] args) throws IOException {
//UDP组播接收数据
//1、创建接收端的 MulticastSocket(10000)对象,相当于对接码头,与单播不同
//2、创建空包裹,用于接收数据,相当于创建一个包裹,准备接收数据
//比单播多一步:把当前电脑添加到这个组中
//3、调用DatagramSocket对象的receive()方法接收数据,并把数据放入箱子
//4、解析数据包,并在控制台展示
//5、释放资源,关闭码头
//与单播区别1:
MulticastSocket ms = new MulticastSocket(10000);
//DatagramPacket(byte[] buf, int length)
//构造一个 DatagramPacket用于接收长度的数据包 length 。
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//与单播区别2:把当前计算机绑定一个组播地址,表示添加到这一组中
ms.joinGroup(InetAddress.getByName("224.0.1.0"));//与发送端的组播地址相同
ms.receive(dp);
byte[] data = dp.getData();//获取数据,其实直接用上面的bytes也行
int length = dp.getLength();
System.out.println(new String(data,0,length));
//System.out.println(new String(bytes,length));
ms.close();
}
}
广播
public class UdpClient2 {
public static void main(String[] args) throws IOException {
//UDP广播发送数据
//1、创建发送端的 DatagramSocket对象,相当于码头
//2、创建数据,并且把数据打包(DatagramPacket),相当于包裹
//3、调用DatagramSocket对象的send方法发送数据,相当于码头发送包裹。单播传IP,广播传广播地址255.255.255.255
//4、释放资源,相当于关闭码头
DatagramSocket ds = new DatagramSocket();
String s = "hello,广播";
byte[] bytes = s.getBytes();
//与单播区别:单播传IP,广播传广播地址255.255.255.255
InetAddress address = InetAddress.getByName("255.255.255.255");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
ds.send(dp);
ds.close();
}
}
public class UdpServer2 {
public static void main(String[] args) throws IOException {
//UDP广播接收数据:与单播一样,没区别
//1、创建接收端的 DatagramSocket对象,相当于对接码头
//2、创建空包裹,用于接收数据,相当于创建一个包裹,准备接收数据
//3、调用DatagramSocket对象的receive()方法接收数据,并把数据放入箱子
//4、解析数据包,并在控制台展示
//5、释放资源,关闭码头
DatagramSocket ds = new DatagramSocket(10000);
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
ds.receive(dp);
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println(new String(data,0,length));
ds.close();
}
}
TCP
public class ClientDemo {
public static void main(String[] args) throws IOException {
//发送数据的步骤
//1、创建客户端Socket对象,与指定的服务端链接
//Socket(ip地址,端口号)
//2、获取输出流,写数据,用Socket对象调用getOutputStream()
//OutputStream getOutputStream()
//3、释放资源
Socket socket = new Socket("127.0.0.1",10000);
OutputStream outputStream = socket.getOutputStream();
String s = "hello";
byte[] bytes = s.getBytes();
outputStream.write(bytes);
/* while (true){
}*/
outputStream.close();
socket.close();
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
//接收数据的步骤
//1、创建服务器端的Socket对象
//ServerSocket(端口号)
//2、监听客户端连接,等待连接,返回一个Socket对象。一直等待连接,死等下去(阻塞),直到连接,创建对象
//Socket accept()
//获取输入流,读数据,并把数据显示在控制台,用Socket对象对象调用inputStream()
//InputStream inputStream()
//3、释放资源
ServerSocket serverSocket = new ServerSocket(10000);
System.out.println("等待连接中。。。。");
Socket socket = serverSocket.accept();
System.out.println("连接成功!");
InputStream inputStream = socket.getInputStream();
int b;
while ((b = inputStream.read())!=-1){//read也存在阻塞,在Client中关流时,给此处的read写一个结束标记,不然在这四等
System.out.print((char)b);
}
System.out.println("");
System.out.println("Client关流成功,read结束阻塞");
inputStream.close();
socket.close();
serverSocket.close();
}
}
public class ClientTest {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",10001);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("你好");
bw.newLine();
bw.flush();
//关流,让Server中read能结束,但不能用close()方法
socket.shutdownOutput();//仅仅关闭输出流,并写出一个结束标记
/* 中文乱码,没有字符流方法,用转换流
InputStream inputStream = socket.getInputStream();
int b;
while ((b = inputStream.read())!=-1){
System.out.println((char)b);
}*/
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = br.readLine())!=null){
System.out.println(line);
}
//System.out.println("看看爹执行了吗?");
bw.close();
br.close();
socket.close();
}
}
public class ServerTest {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(10001);
Socket socket = serverSocket.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = br.readLine())!=null){
System.out.println(line);
}
//System.out.println("看看爹执行了吗?");
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("你谁啊");
bw.newLine();
bw.flush();
br.close();
bw.close();
socket.close();
serverSocket.close();
}
}
public class ClientTest2 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",10002);
//本地的流,用于读取本地文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("Socket\\ClientDir\\1.jpeg"));//用缓冲流包装一下
//写到服务器,网络的流
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());//用缓冲流包装一下
int b;
while ((b = bis.read())!=-1){
bos.write(b);//通过网络写到服务器中
}
socket.shutdownOutput();//给服务器read一个结束标记
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = br.readLine())!=null){
System.out.println(line);
}
socket.close();
bis.close();//关本地的流,网络的流随着socket.close()关闭而关闭
}
}
public class ServerTest2 {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(10002);
//实现多次连接客户端,但无法实现多个客户端同时连接服务端.要用线程,连接一个客户端开启一个线程,进行同样的数据操作
//但是多线程浪费资源,使用线程池改进
ThreadPoolExecutor pool = new ThreadPoolExecutor(
3,
10,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
while (true) {
Socket socket = serverSocket.accept();
ThreadSocket threadSocket = new ThreadSocket(socket);
//new Thread(threadSocket).start();
pool.submit(threadSocket);
}
//serverSocket.close();
}
}
public class ThreadSocket implements Runnable{
private Socket socket;
public ThreadSocket(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedOutputStream bos = null;
try {
//网络的流,从客户端那里读取数据
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
//本地的流,把数据写到本地
//第二次上传文件会覆盖之前的,因为名字相同。用UUID.randomUUID()方法生成随机文件名,机会不会重名
bos = new BufferedOutputStream(new FileOutputStream("Socket\\ServerDir\\"+ UUID.randomUUID().toString()+".jpeg"));
int b;
while ((b = bis.read())!=-1){
bos.write(b);
}
//给客户端反馈
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("上传成功");
bw.newLine();
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bos!=null){
try {
bos.close();//关本地的流,网络的流随着socket.close()和serverSocket.close();关闭而关闭
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
|