Java_网络编程

网络编程

定义:

        网络编程就是计算机跟计算机之间通过网络进行数据传输

常见的软件架构:

        1.C/S(Client/Server):客户端/服务器模式

        2.B/S(Browser/Server):浏览器/服务器模式

区别和优缺点:

        C/S需要开发客户端和服务端,

        B/S不需要开发客户端。

        C/S适合定制专业化的软件如:IDEA、一些画面精美的大型游戏,

        B/S适合移动互联网应用,可以在任何地方随时访问的系统。

网络编程三要素

1.IP:

        设备在网络中的地址,是唯一的标识

IP的作用:

        设备在网络中的地址,是唯一的标识

IPv4有什么特点:

        是目前的主流方案

        最多只有2^32个ip,目前已经用完了

IPv6有什么特点:

        为了解决IPv4不够用而出现的

        最多有2^128个ip

IPv4小细节:

        1.现在如何解决IPv4不够的问题?

                利用局域网IP解决IP不够的问题

        2.特殊的IP:

                127.0.0.1(永远表示本机)

        3.常见的两个CMD命令:

                ipconfig:查看本机IP地址

                ping(+IP地址/网址):检查网络是否连通

InetAddress类的使用:
        代码演示:
public class netAddressDemo1 {public static void main(String[] args) throws UnknownHostException {//InetAddress类的使用/*static InetAddress getByName(String host)   确定主机名称的IP地址,主机名称可以是机器名称,也可以是IP地址String getHostName()                        获取此IP地址的主机名String getHostAddress()                     返回文本显示中的IP地址字符串*///获取InetAddress对象InetAddress address = InetAddress.getByName("LAPTOP-8RU5E3RO");System.out.println(address);//String getHostName()  获取此IP地址的主机名String hostName = address.getHostName();System.out.println(hostName);//String getHostAddress()   返回文本显示中的IP地址字符串String hostAddress = address.getHostAddress();System.out.println(hostAddress);}
}
运行结果:

2.端口号:

        应用程序在设备中唯一的标识

端口号介绍:

        由两个字节表示的整数,取值范围:0~65535,其中0~1023之间的端口号用于一些知名的网络服务或者应用。我们自己使用1024以上的端口号就可以了。

        注意:一个端口号只能被一个应用程序使用

3.协议:

        数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp

UDP协议:

        用户数据报协议(User Datagram Protocol)

        UDP是面向无连接通信协议

        速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据

        适用情况有:网络会议、在线视频、在线通话等

发送数据:
        步骤:

                1.创建DatagramSocket对象(快递公司)

        (参数为端口号,空参表示在所有可用的端口中随机使用一个,有参则使用指定的端口号)

                2.打包数据

                3.发送数据

                4.释放资源

        代码演示:
public class SendMessageDemo1 {public static void main(String[] args) throws IOException {/*1.创建DatagramSocket对象(快递公司)2.打包数据3.发送数据4.释放资源*///1.创建DatagramSocket对象(快递公司)DatagramSocket ds = new DatagramSocket();//2.打包数据String str = "要发送的数据";byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("127.0.0.1");int port = 10086;DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);//3.发送数据ds.send(dp);//4.释放资源ds.close();}
}
 接收数据:
        步骤:

                1.创建DatagramSocket对象(快递公司)

        (接收的时候必须要绑定端口,且绑定的端口要跟发送的端口保持一致)

                2.接收数据包

                3.解析数据包

                4.释放资源

        代码演示:
public class ReceiveMessageDemo1 {public static void main(String[] args) throws IOException {/*1.创建DatagramSocket对象(快递公司)(接收的时候必须要绑定端口,且绑定的端口要跟发送的端口保持一致)2.接收数据包3.解析数据包4.释放资源*///1.创建DatagramSocket对象(快递公司)DatagramSocket ds = new DatagramSocket(10086);//2.接收数据包byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes,bytes.length);ds.receive(dp);//该方法是阻塞的,即这句代码运行后,不接受到消息,是不会往下继续运行的//3.解析数据包byte[] data = dp.getData();int length = dp.getLength();InetAddress address = dp.getAddress();int port = dp.getPort();System.out.println("从" + address + "端口号为" + port+ "接收到长度为" + length + "的数据:" + new String(data,0,length));//4.释放资源ds.close();}
}
运行结果:

简易聊天室小练习:

        按照下面的要求实现程序:

        UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束

        UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收

代码演示:

接收端:

public class ReceiveMessageDemo2 {public static void main(String[] args) throws IOException {//1.创建DatagramSocket对象DatagramSocket ds = new DatagramSocket(10086);//2.接收数据包byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes,bytes.length);while (true) {ds.receive(dp);//3.解析数据String ip = dp.getAddress().getHostAddress();String hostName = dp.getAddress().getHostName();byte[] data = dp.getData();System.out.println("接收到从IP地址为:" + ip + "主机名为:" + hostName + "的数据:" + new String(data));}}
}

发送端:

public class SendMessageDemo2 {public static void main(String[] args) throws IOException {/*按照下面的要求实现程序:UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收*///1.创建DatagramSocket对象DatagramSocket ds = new DatagramSocket();//2.打包数据Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入你要发送的内容(发送886则程序关闭)");String message = sc.nextLine();if("886".equals(message)) {break;}byte[] bytes = message.getBytes();InetAddress address = InetAddress.getByName("127.0.0.1");int port = 10086;DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);//3.发送数据ds.send(dp);}//4.释放资源ds.close();}
}
运行结果:

发送端:

接收端:

UDP的三种通讯方式

        1.单播

                前面的代码就是单播

        2.组播

                组播地址:224.0.0.0 ~ 239.255.255.255

                其中224.0.0.0 ~ 224.0.0.255为预留的组播地址

        3.广播

                广播地址:255.255.255.255

        因为前面的代码就是单播,这里只演示组播和广播代码

组播代码演示:

发送端:

public class SendMessageDemo {public static void main(String[] args) throws IOException {/*1.创建DatagramSocket对象(快递公司)2.打包数据3.发送数据4.释放资源*///1.创建MulticastSocket对象(快递公司)MulticastSocket ms = new MulticastSocket();//2.打包数据String str = "要发送的数据";byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("224.0.0.1");int port = 10000;DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);//3.发送数据ms.send(dp);//4.释放资源ms.close();}
}

三个接收端:

接收端1:

public class ReceiveMessageDemo1 {public static void main(String[] args) throws IOException {//1.创建MulticastSocket对象MulticastSocket ms = new MulticastSocket(10000);//2.将本机添加到224.0.0.1这一组当中InetAddress address = InetAddress.getByName("224.0.0.1");ms.joinGroup(address);//3.接收数据包byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes,bytes.length);ms.receive(dp);//4.解析数据String ip = dp.getAddress().getHostAddress();String hostName = dp.getAddress().getHostName();byte[] data = dp.getData();System.out.println("接收到IP地址为:" + ip + "主机名为:" + hostName + "的数据:" + new String(data));//5.释放资源ms.close();}
}

接收端2:

public class ReceiveMessageDemo2 {public static void main(String[] args) throws IOException {//1.创建MulticastSocket对象MulticastSocket ms = new MulticastSocket(10000);//2.将本机添加到224.0.0.1这一组当中InetAddress address = InetAddress.getByName("224.0.0.1");ms.joinGroup(address);//3.接收数据包byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes,bytes.length);ms.receive(dp);//4.解析数据String ip = dp.getAddress().getHostAddress();String hostName = dp.getAddress().getHostName();byte[] data = dp.getData();System.out.println("接收到IP地址为:" + ip + "主机名为:" + hostName + "的数据:" + new String(data));//5.释放资源ms.close();}
}

接收端3:

public class ReceiveMessageDemo3 {public static void main(String[] args) throws IOException {//1.创建MulticastSocket对象MulticastSocket ms = new MulticastSocket(10000);//2.将本机添加到224.0.0.1这一组当中InetAddress address = InetAddress.getByName("224.0.0.1");ms.joinGroup(address);//3.接收数据包byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes,bytes.length);ms.receive(dp);//4.解析数据String ip = dp.getAddress().getHostAddress();String hostName = dp.getAddress().getHostName();byte[] data = dp.getData();System.out.println("接收到IP地址为:" + ip + "主机名为:" + hostName + "的数据:" + new String(data));//5.释放资源ms.close();}
}
运行结果:

接收端1:

接收端2:

接收端3:

广播代码演示:

将单播的传输目的地址改为255.255.255.255即可

public class SendMessageDemo {public static void main(String[] args) throws IOException {/*1.创建DatagramSocket对象(快递公司)2.打包数据3.发送数据4.释放资源*///1.创建DatagramSocket对象(快递公司)DatagramSocket ds = new DatagramSocket();//2.打包数据String str = "要发送的数据";byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("255.255.255.255");int port = 10086;DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);//3.发送数据ds.send(dp);//4.释放资源ds.close();}
}

TCP协议:

        传输控制协议TCP(Transmission Control Protocol)

        TCP协议是面向连接的通信协议。

        速度慢,没有大小限制,数据安全。

        适用情况有:下载软件、文字聊天、发送邮件等

TCP通信程序:

        TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象

        通信之前要保证连接已经建立

        通过Socket产生IO流来进行网络通信

编写步骤:

        客户端:

                ①创建客户端的Socket对象(Socket)与指定服务端连接(创建对象的同时会连接服务器)

                    Socket(String host, int port)

                ②获取输出流,写数据(写出的数据应为字节数组)

                    OutputStream getOutputStream()

                ③释放资源

                    void close()

        服务端:

                ①创建服务器端的Socket对象(ServerSocket)

                    ServerSocket(int port)

                ②监听客户端连接,返回一个Socket对象(也是阻塞方法)

                    Socket accept()

                ③获取输入流,读数据,并把数据显示在控制台

                    InputStream getInputStream()

                ④释放资源

                    void close()

代码演示1:

客户端:

public class Client {public static void main(String[] args) throws IOException {/*1.创建客户端的Socket对象(Socket)与指定服务端连接Socket(String host, int port)2.获取输出流,写数据OutputStream getOutputStream()3.释放资源void close()*///1.创建客户端的Socket对象(Socket)与指定服务端连接Socket socket = new Socket("127.0.0.1",10000);//2.获取输出流,写数据OutputStream os = socket.getOutputStream();os.write("aaa".getBytes());//注意要写字节数组//3.释放资源os.close();socket.close();}
}

服务端:

public class Server {public static void main(String[] args) throws IOException {/*1.创建服务器端的Socket对象(ServerSocket)ServerSocket(int port)2.监听客户端连接,返回一个Socket对象Socket accept()3.获取输入流,读数据,并把数据显示在控制台InputStream getInputStream()4.释放资源void close()*///1.创建服务器端的Socket对象(ServerSocket)ServerSocket ss = new ServerSocket(10000);//2.监听客户端连接,返回一个Socket对象Socket socket = ss.accept();//3.获取输入流,读数据,并把数据显示在控制台InputStream is = socket.getInputStream();int b;while ((b = is.read()) != -1) {System.out.print((char) b);}//4.释放资源is.close();socket.close();ss.close();}
}
运行结果1:

注意:

        这种方式发送中文信息会产生乱码,因为汉字转换成字节数组后字节流是一个一个字节去读的。

        下面是可以传输中文的代码:

代码演示2

 客户端:

public class Client {public static void main(String[] args) throws IOException {/*1.创建客户端的Socket对象(Socket)与指定服务端连接Socket(String host, int port)2.获取输出流,写数据OutputStream getOutputStream()3.释放资源void close()*///1.创建客户端的Socket对象(Socket)与指定服务端连接Socket socket = new Socket("127.0.0.1",10000);//2.获取输出流,写数据OutputStream os = socket.getOutputStream();os.write("你好啊".getBytes());//注意要写字节数组//3.释放资源os.close();socket.close();}
}

服务端:

public class Server {public static void main(String[] args) throws IOException {/*1.创建服务器端的Socket对象(ServerSocket)ServerSocket(int port)2.监听客户端连接,返回一个Socket对象Socket accept()3.获取输入流,读数据,并把数据显示在控制台InputStream getInputStream()4.释放资源void close()*///1.创建服务器端的Socket对象(ServerSocket)ServerSocket ss = new ServerSocket(10000);//2.监听客户端连接,返回一个Socket对象Socket socket = ss.accept();//3.获取输入流,读数据,并把数据显示在控制台InputStream is = socket.getInputStream();//使用转换流将字节输入流转换成字符输入流(也可以在转换成字符缓冲输入流)InputStreamReader isr = new InputStreamReader(is);int b;while ((b = isr.read()) != -1) {System.out.print((char) b);}//4.释放资源socket.close();ss.close();}
}

运行结果2:

三次握手:

四次挥手:

参考模型
OSI参考模型:

        

应用层
表示层
会话层
传输层
网络层
数据链路层
物理层
TCP/IP参考模型:
应用层
传输层
网络层
物理+数据链路层

练习题

练习一:

        多发多收

                客户端:多次发送数据,发送886时结束

                服务端:接收多次数据,并打印

代码演示:
客户端:
public class Client {public static void main(String[] args) throws IOException {/*多发多收客户端:多次发送数据,发送886时结束服务端:接收多次数据,并打印*///1.创建Socket对象Socket socket = new Socket("127.0.0.1",10001);//2.获取输出流OutputStream os = socket.getOutputStream();Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入您要发送的内容");String message = sc.nextLine();if("886".equals(message)) {break;}os.write(message.getBytes());}//释放资源socket.close();}
}
服务端:
public class Server {public static void main(String[] args) throws IOException {//1.创建ServerSocket对象ServerSocket ss = new ServerSocket(10001);//2.监听客户端连接,返回Socket对象Socket socket = ss.accept();//3.获取输入流BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));int b;while ((b = br.read()) != -1) {System.out.print((char) b);}//4.释放资源socket.close();ss.close();}
}
运行结果:
客户端:

服务端:

练习二:

        接收和反馈

                客户端:发送一条数据,接收服务端反馈的消息并打印

                服务端:接收数据并打印,再给客户端反馈消息

代码演示:
客户端:
public class Client {public static void main(String[] args) throws IOException {/*接收和反馈客户端:发送一条数据,接收服务端反馈的消息并打印服务端:接收数据并打印,再给客户端反馈消息*///1.创建Socket对象Socket socket = new Socket("127.0.0.1",10001);//2.获取输出流//发送一条数据OutputStream os = socket.getOutputStream();os.write("你好".getBytes());//终止输出流,终止服务端的read方法socket.shutdownOutput();//接收服务端反馈的消息InputStreamReader isr = new InputStreamReader(socket.getInputStream());int b;while ((b = isr.read()) != -1) {System.out.print((char) b);}//3.释放资源socket.close();}
}
服务端:
public class Server {public static void main(String[] args) throws IOException {//1.创建ServerSocket对象ServerSocket ss = new ServerSocket(10001);//2.监听客户端连接,返回Socket对象Socket socket = ss.accept();//3.获取输入流InputStreamReader isr = new InputStreamReader(socket.getInputStream());int b;//注意:read方法会从连接通道中读取数据//但是,需要有一个结束标记,此时的循环才会停止//否则,程序就会一直停在read方法这里,等待读取下面的数据while ((b = isr.read()) != -1) {System.out.print((char) b);}//输出反馈消息OutputStream os = socket.getOutputStream();os.write("你也好".getBytes());//4.释放资源socket.close();ss.close();}
}
运行结果:
客户端:

服务端:

练习三:

        上传文件

                客户端:将本地文件上传到服务器。接收服务器的反馈

                服务器:接收客户端上传的文件,上传完毕之后给出反馈

代码演示:
客户端:
public class Client {public static void main(String[] args) throws IOException {/*上传文件客户端:将本地文件上传到服务器。接收服务器的反馈服务器:接收客户端上传的文件,上传完毕之后给出反馈*///创建Socket对象Socket socket = new Socket("127.0.0.1",10001);//获取输出流BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());//读取文件BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\Han\\IdeaProjects\\mysocketnet\\clientdir\\img.png"));byte[] bytes = new byte[1024];int len;while((len = bis.read(bytes)) != -1) {//写出文件bos.write(bytes,0,len);}bis.close();bos.flush();//终止输出流socket.shutdownOutput();//接收反馈BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String feedback = br.readLine();System.out.println(feedback);//释放资源socket.close();}
}
服务端:
public class Server {public static void main(String[] args) throws IOException {//创建ServerSocket对象ServerSocket ss = new ServerSocket(10001);//监听客户端连接,返回Socket对象Socket socket = ss.accept();//获取输入流BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\Han\\IdeaProjects\\mysocketnet\\serverdir\\img.png"));byte[] bytes = new byte[1024];int len;while((len = bis.read(bytes)) != -1) {//存储文件bos.write(bytes,0,len);}bos.flush();bos.close();//反馈已接收文件信息BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("已接收文件");bw.flush();//释放资源socket.close();ss.close();}
}
运行结果:
客户端:

且图片正常复制

练习四:

        解决上一题文件名重复问题

代码演示:
客户端:

        没有变化

public class Client {public static void main(String[] args) throws IOException {/*解决上一题文件名重复问题*///创建Socket对象Socket socket = new Socket("127.0.0.1",10001);//获取输出流BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());//读取文件BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\Han\\IdeaProjects\\mysocketnet\\clientdir\\img.png"));byte[] bytes = new byte[1024];int len;while((len = bis.read(bytes)) != -1) {//写出文件bos.write(bytes,0,len);}bis.close();bos.flush();//终止输出流socket.shutdownOutput();//接收反馈BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String feedback = br.readLine();System.out.println(feedback);//释放资源socket.close();}
}
服务端:

        新添加用UUID类来生成随机唯一名字

public class Server {public static void main(String[] args) throws IOException {//创建ServerSocket对象ServerSocket ss = new ServerSocket(10001);//监听客户端连接,返回Socket对象Socket socket = ss.accept();//获取输入流BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());//利用UUID获取随机文件名称String name = UUID.randomUUID().toString().replace("-", "");//定义输出流输出到文件BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\Han\\IdeaProjects\\mysocketnet\\serverdir\\" + name + ".png"));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {//存储文件bos.write(bytes, 0, len);}bos.flush();bos.close();//反馈已接收文件信息BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("已接收文件");bw.flush();//释放资源socket.close();ss.close();}
}
运行结果:
客户端:

且图片正常复制,运行两次后结果:

练习五:

        上传文件(多线程版)

                想要服务器不停止,能接收很多用户上传的图片。

                该怎么做? 提示:可以用多线程

代码演示:
客户端:
public class Client {public static void main(String[] args) throws IOException {/*上传文件(多线程版)想要服务器不停止,能接收很多用户上传的图片。该怎么做?提示:可以用多线程*///创建Socket对象Socket socket = new Socket("127.0.0.1",10001);//获取输出流BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());//读取文件BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\Han\\IdeaProjects\\mysocketnet\\clientdir\\img.png"));byte[] bytes = new byte[1024];int len;while((len = bis.read(bytes)) != -1) {//写出文件bos.write(bytes,0,len);}bis.close();bos.flush();//终止输出流socket.shutdownOutput();//接收反馈BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String feedback = br.readLine();System.out.println(feedback);//释放资源socket.close();}
}
服务端:
public class Server {public static void main(String[] args) throws IOException {//创建ServerSocket对象ServerSocket ss = new ServerSocket(10001);while (true) {//监听客户端连接,返回Socket对象Socket socket = ss.accept();//创建线程MyRunnable mr = new MyRunnable(socket);Thread thread = new Thread(mr);thread.start();}}
}
MyRunnable类:
public class MyRunnable implements Runnable {Socket socket;public MyRunnable(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {//获取输入流BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());//利用UUID获取随机文件名称String name = UUID.randomUUID().toString().replace("-", "");//定义输出流输出到文件BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\Han\\IdeaProjects\\mysocketnet\\serverdir\\" + name + ".png"));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {//存储文件bos.write(bytes, 0, len);}bos.flush();bos.close();//反馈已接收文件信息BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("已接收文件");bw.flush();} catch (IOException e) {throw new RuntimeException(e);} finally {//释放资源if(socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
运行结果:
客户端:

且图片正常复制

练习六:

        上传文件(线程池优化)

        频繁创建线程并销毁非常浪费系统资源,所以需要用线程池优化

代码演示:
客户端:
public class Client {public static void main(String[] args) throws IOException {/*上传文件(线程池优化)频繁创建线程并销毁非常浪费系统资源,所以需要用线程池优化*///创建Socket对象Socket socket = new Socket("127.0.0.1",10001);//获取输出流BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());//读取文件BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\Han\\IdeaProjects\\mysocketnet\\clientdir\\img.png"));byte[] bytes = new byte[1024];int len;while((len = bis.read(bytes)) != -1) {//写出文件bos.write(bytes,0,len);}bis.close();bos.flush();//终止输出流socket.shutdownOutput();//接收反馈BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String feedback = br.readLine();System.out.println(feedback);//释放资源socket.close();}
}
服务端:
public class Server {public static void main(String[] args) throws IOException {//创建ServerSocket对象ServerSocket ss = new ServerSocket(10001);//创建线程池对象ThreadPoolExecutor pool = new ThreadPoolExecutor(3,//核心线程数16,//总线程数60,//空闲时间TimeUnit.SECONDS,//空闲时间单位new ArrayBlockingQueue<>(2),//队列长度Executors.defaultThreadFactory(),//线程工厂new ThreadPoolExecutor.AbortPolicy()//拒绝策略);while (true) {//监听客户端连接,返回Socket对象Socket socket = ss.accept();//交给线程池pool.submit(new MyRunnable(socket));}}
}
MyRunnable类:
public class MyRunnable implements Runnable {Socket socket;public MyRunnable(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {//获取输入流BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());//利用UUID获取随机文件名称String name = UUID.randomUUID().toString().replace("-", "");//定义输出流输出到文件BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\Han\\IdeaProjects\\mysocketnet\\serverdir\\" + name + ".png"));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {//存储文件bos.write(bytes, 0, len);}bos.flush();bos.close();//反馈已接收文件信息BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("已接收文件");bw.flush();} catch (IOException e) {throw new RuntimeException(e);} finally {//释放资源if(socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
运行结果:
客户端:

且图片正常复制

练习七:

        BS(接收浏览器的消息并打印)

                客户端:不需要写

                服务器:接收数据并打印

代码演示:
服务端:
public class Server {public static void main(String[] args) throws IOException {/*BS(接收浏览器的消息并打印)客户端:不需要写服务器:接收数据并打印*///1.创建ServerSocket对象ServerSocket ss = new ServerSocket(10001);//2.监听客户端连接,返回Socket对象Socket socket = ss.accept();//3.获取输入流BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));int b;while ((b = br.read()) != -1) {System.out.print((char) b);}//4.释放资源socket.close();ss.close();}
}

        开启服务端

打开浏览器,在网址搜索栏上输入127.0.0.1:10001(服务端启动的端口号)

运行结果:

大作业:

        控制台版聊天室

代码演示:

Client类:
public class Client {public static void main(String[] args) throws IOException {/*服务器已经连接成功==============欢迎来到聊天室================1登录2注册请输入您的选择:*///创建Socket对象Socket socket = new Socket("127.0.0.1",10001);ClientRunnable cr = new ClientRunnable(socket);Scanner sc = new Scanner(System.in);System.out.println("服务器已经连接成功");while (true) {System.out.println("==============欢迎来到聊天室================");System.out.println("1登录");System.out.println("2注册");System.out.print("请输入您的选择:");//读取用户输入信息String select = sc.nextLine();if (select.equals("1")) {System.out.println("点击了登录");if (loginEvent(socket)) {//创建线程进入聊天室聊天Thread thread = new Thread(cr);thread.start();//开始聊天while(true) {System.out.println("请输入想说的话:");String message = sc.nextLine();//传给服务端BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(message);bw.newLine();bw.flush();}}} else if (select.equals("2")) {System.out.println("点击了注册");if (registerEvent()) {break;}} else {System.out.println("没有这个选项,请重新输入:");}}}//注册事件private static boolean registerEvent() throws IOException {Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String username = sc.nextLine();System.out.println("请输入密码:");String password = sc.nextLine();System.out.println("请再次输入密码:");String passwordAgain = sc.nextLine();//两次输入的密码不一致if (!(password.equals(passwordAgain))) {System.out.println("两次输入的密码不一致");return false;}//用户名或密码格式有误if (!(usernameFormatVerify(username) && passwordFormatVerify(password))) {System.out.println("用户名或密码格式有误");return false;}//查看用户名是否已存在BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\Han\\IdeaProjects\\mychatroom\\src\\com\\han\\chatroom\\usersinfo"));ArrayList<String> list = new ArrayList<>();String line;while ((line = br.readLine()) != null) {list.add(line);}br.close();for (String str : list) {String us = str.split("=")[0];if (username.equals(us)) {System.out.println("用户名已存在");return false;}}//将新用户名和密码存入文件BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\Han\\IdeaProjects\\mychatroom\\src\\com\\han\\chatroom\\usersinfo", true));//username=zhangsan&password=123bw.newLine();bw.write(username + "=" + password);bw.flush();bw.close();System.out.println("注册成功");return true;}//登录事件private static boolean loginEvent(Socket socket) throws IOException {Scanner sc = new Scanner(System.in);System.out.println("请输入您的用户名:");String username = sc.nextLine();System.out.println("请输入您的密码:");String password = sc.nextLine();StringBuffer sb = new StringBuffer();//以下面这种形式将用户名密码传输给服务器BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//username=zhangsan&password=123if (usernameFormatVerify(username) && passwordFormatVerify(password)) {sb.append("username=").append(username).append("&password=").append(password);//传输给服务端//获取输出流bw.write(sb.toString());bw.newLine();bw.flush();//接收输入流并打印BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String result = br.readLine();System.out.println(result);if("用户名密码正确,登录成功".equals(result)) {return true;}}return false;}//验证用户名格式public static boolean usernameFormatVerify(String username) {//用户名要唯一,长度:6~18位,纯字母,不能有数字或其他符号。int len = username.length();//长度:6~18位if (len < 6 || len > 18) {System.out.println("用户名长度应为6~18位");return false;}//纯字母for (int i = 0; i < len; i++) {char ch = username.charAt(i);if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) {System.out.println("用户名应为纯字母,不能有数字或其他符号");return false;}}return true;}//验证密码格式public static boolean passwordFormatVerify(String password) {//密码长度3~8位。第一位必须是小写或者大小的字母,后面必须是纯数字。int len = password.length();//长度3~8位if (len < 3 || len > 8) {System.out.println("密码长度应为3~8位");return false;}//第一位必须是小写或者大小的字母,后面必须是纯数字char start = password.charAt(0);if (!((start >= 'a' && start <= 'z') || (start >= 'A' && start <= 'Z'))) {System.out.println("密码第一位必须是小写或者大小的字母,后面必须是纯数字");return false;}char[] arr = new char[len - 1];password.getChars(1, len, arr, 0);for (char ch : arr) {if (!(ch >= '0' && ch <= '9')) {System.out.println("密码第一位必须是小写或者大小的字母,后面必须是纯数字");return false;}}return true;}
}
CilientRunnable类:
public class ClientRunnable implements Runnable {Socket socket;public ClientRunnable(Socket socket) {this.socket = socket;}@Overridepublic void run() {//获取输入流try {while (true) {BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String message = br.readLine();System.out.println(message);}} catch (IOException e) {throw new RuntimeException(e);}}
}
Server类:
public class Server {//创建集合管理登录成功的Socket对象static ArrayList<Socket> socketList = new ArrayList<>();public static void main(String[] args) throws IOException {//创建ServerSocket对象ServerSocket ss = new ServerSocket(10001);while (true) {//监听客户端连接,获得Socket对象Socket socket = ss.accept();//只要来一个客户端就创建一个线程ServerRunnable sr = new ServerRunnable(socketList,socket);Thread thread = new Thread(sr);thread.start();}}}
ServerRunnable类:
public class ServerRunnable implements Runnable{ArrayList<Socket> socketList;Socket socket;public ServerRunnable(ArrayList<Socket> socketList, Socket socket) {this.socketList = socketList;this.socket = socket;}@Overridepublic void run() {String rebackStr;try {//获取输入流BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String str = br.readLine();//username=zhangsan&password=123String username = str.split("&")[0].split("=")[1];String password = str.split("&")[1].split("=")[1];//判断用户名密码是否正确//读取文件中的用户名密码HashMap<String,String> hm = new HashMap<>();BufferedReader br2 = new BufferedReader(new FileReader("C:\\Users\\Han\\IdeaProjects\\mychatroom\\src\\com\\han\\chatroom\\usersinfo"));String line;while((line = br2.readLine()) != null) {String[] arr = line.split("=");hm.put(arr[0],arr[1]);}//判断加回写提示rebackStr = judge(hm,username,password);//回写BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(rebackStr);bw.newLine();bw.flush();if("用户名密码正确,登录成功".equals(rebackStr)) {//登录成功了socketList.add(socket);while (true) {//读取数据String message = username + "发来消息:" + br.readLine();System.out.println(message);//群发消息for (Socket socket : socketList) {BufferedWriter bw2 = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw2.write(message);bw2.newLine();bw2.flush();}}} else {//登录失败System.out.println("登录失败");}} catch (IOException e) {throw new RuntimeException(e);}}public static String judge(HashMap<String,String> hm, String username, String password) {int flag = 0;Set<Map.Entry<String, String>> entries = hm.entrySet();for (Map.Entry<String, String> entry : entries) {if(entry.getKey().equals(username)) {//有相同用户名flag++;if(entry.getValue().equals(password)) {return "用户名密码正确,登录成功";}}}if(flag == 0) {return "用户名不存在,登录失败";} else {return "密码错误,登录失败";}}
}

运行结果:

服务端:

客户端1:

客户端2:

客户端3:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/14727.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安全系列---入门

目录 xss注入问题Authenticator认证器 xss注入问题 现象&#xff1a;前端显示内容非预期原因&#xff1a;反射型注入和存储型注入&#xff0c;本质都是利用输入框输入一段js代码。解决&#xff1a;利用html的转义解析&#xff0c;当浏览器遇到HTML转义符时&#xff0c;它会将其…

深入理解MySQL:查询表的历史操作记录

摘要&#xff1a;在数据库管理中&#xff0c;了解如何查询表的历史操作记录对于追踪数据变更、审计数据以及恢复误操作至关重要。本文将深入探讨MySQL中查询表的历史操作记录的方法&#xff0c;并提供多个实例以帮助读者更好地理解和应用这一技术。 引言 在数据库管理中&#…

Kivy.garden.NavigationDrawer

totally copied from github opensource code. Just a translation and ideas with idividuals ideas to share its use for all people using chinese. Copyright © 2013 Alexander Taylor 开源免责免费使用声明: #Permission is hereby granted, free of charge, to any…

【SpringBoot项目开发】查看购物车和清空购物车实现

查看和清空购物车的注意事项&#xff1a; 需要查看登录用户购物车中所有的信息&#xff0c;但是请求参数中可以不包含用户id&#xff0c;因为请求时会附带一个token&#xff0c;从token中能解析到用户id。 return shoppingCartMapper.list(ShoppingCart.builder().userId(Bas…

GQL图查询语言:高效处理复杂图数据

GQL是一种新型的查询语言&#xff0c;它可以处理复杂图数据&#xff0c;以提供比传统 SQL更快、更高效的查询方式。GQL图查询语言具有可扩展性&#xff0c;可以使用最少的编程知识来访问图数据库。在本文中&#xff0c;我们将探讨 GQL的概念和实际使用案例。同时&#xff0c;我…

C++: 多态

目录 一、多态的概念 二、多态的定义及实现 2.1虚函数 2.2虚函数的重写 2.3多态的构成条件 2.4虚函数重写的两个例外 1.协变 2.析构函数的重写 2.5虚函数重写的实质 2.6override 和 final&#xff08;C11&#xff09; 1.final 2.override 2.7重载、覆盖&#xff0…

go语言之变量

go是静态类型语言&#xff0c;因此变量是具有明确类型的&#xff0c;编译器也会检查变量类型的正确性 我们从计算机系统的角度来讲&#xff0c;变量就是一段或者多段内存&#xff0c;用于存储数据 文章目录 变量声明标准格式简便格式不指定变量类型批量声明简短格式 匿名变量变…

http协议报文头部结构解释

http协议报文头部结构 请求报文 报文解释 请求报文由三部分组成&#xff1a;开始行、首部行、实体主体 开始行&#xff1a;请求方法&#xff08;get、post&#xff09;url版本 CRLE 方法描述GET请求指定页面信息&#xff0c;并返回实体主体HEAD类似get要求&#xff0c;只不…

WXML模板语法-条件渲染和列表渲染

一、条件渲染 1.wx:if 在小程序中&#xff0c;使用wx:if"{{condition}}"来判断是否需要渲染该代码块,也可以用wx:elif和wx:else来添加else判断 // pages/list/list.js Page({data: {type:1} })<!--pages/list/list.wxml--><view wx:if"{{type 1}}&…

504 Gateway Time-out

问题描述 做Excel导入的功能&#xff0c;由于Excel的数据比较多&#xff0c;需要做处理然后入库&#xff0c;数据量大概200万&#xff0c;所以毫无悬念的导入Excel接口调用超过了一分钟&#xff0c;并且报错&#xff1a;504 gateway timeout。 解决方案 nginx超时限制。路径…

与WAF的“相爱相杀”的RASP

用什么来保护Web应用的安全&#xff1f; 猜想大部分安全从业者都会回答&#xff1a;“WAF&#xff08;Web Application Firewall,应用程序防火墙&#xff09;。”不过RASP&#xff08;Runtime Application Self-Protection&#xff0c;应用运行时自我保护&#xff09;横空出世…

微信小程序-----基础加强(二)

能够知道如何安装和配置vant-weapp 组件库能够知道如何使用MobX实现全局数据共享能够知道如何对小程序的API 进行 Promise 化能够知道如何实现自定义tabBar 的效果 一.使用 npm 包 小程序对 npm 的支持与限制 目前&#xff0c;小程序中已经支持使用 npm 安装第三方包&#x…

采用Java语言开发的(云HIS医院系统源码+1+N模式,支撑运营,管理,决策多位一体)

采用Java语言开发的&#xff08;云HIS医院系统源码1N模式&#xff0c;支撑运营&#xff0c;管理&#xff0c;决策多位一体&#xff09; 是不是网页形式【B/S架构]才是云计算服务? 这是典型的误区! 只要符合上述描述的互联网服务都是云计算服务&#xff0c;并没有规定是网页…

东软联合福建省大数据集团打造“数据要素×医疗健康”服务新模式

5月23日&#xff0c;东软集团与福建省大数据集团有限公司在福州签订战略合作协议。 据「TMT星球」了解&#xff0c;双方将在健康医疗数据要素价值领域展开合作&#xff0c;通过大数据服务&#xff0c;赋能商业保险公司的产品设计和保险两核&#xff0c;打造“数据要素医疗健康…

安卓分身大师4.6.0解锁会员安卓14可用机型伪装双开多开

需登录解锁会员功能&#xff0c;除了加速进入不能&#xff0c; 其他主要功能都是可以使用&#xff0c;由于验证较多一些功能需要特定操作使用&#xff0c;进行伪装时请不要直接伪装&#xff0c;先生成成功后再进行自定义伪装&#xff01;链接&#xff1a;https://pan.baidu.com…

机器人非线性控制方法——线性化与解耦

机器人非线性控制方法是针对具有非线性特性的机器人系统所设计的一系列控制策略。其中&#xff0c;精确线性化控制和反演控制是两种重要的方法。 1. 非线性反馈控制 该控制律采用非线性反馈控制的方法&#xff0c;将控制输入 u 分解为两个部分&#xff1a; α(x): 这是一个与…

设计模式--观察者模式

观察者模式是一种行为设计模式&#xff0c;它定义了对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;它的所有依赖者都会自动收到通知并更新。这种模式在许多应用场景中非常有用&#xff0c;例如在实现事件驱动编程、消息队列、发布-订阅模型以…

vue 引入 emoji 表情包

vue 引入 emoji 表情包 一、安装二、组件内使用 一、安装 npm install --save emoji-mart-vue二、组件内使用 import { Picker } from "emoji-mart-vue"; //引入组件<picker :include"[people,Smileys]" :showSearch"false" :showPreview&q…

秒杀系统如何设计?【面试准备】

秒杀系统如何设计&#xff1f;【面试准备】 前言版权推荐秒杀系统如何设计&#xff1f;库存如何扣减的设计支付-延时队列最后 前言 2023-9-1 16:23:31 公开发布于 2024-5-22 00:09:02 以下内容源自《【面试准备】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话…

找钢集团亮相沙特利雅得建筑行业供应链展会

5月20日-21日&#xff0c;找钢产业互联集团&#xff08;以下简称&#xff1a;找钢集团&#xff09;亮相沙特利雅得建筑行业供应链展会。本次展会由沙特阿拉伯国家住房公司&#xff08;NHC&#xff09;主办&#xff0c;中信建设协办&#xff0c;涵盖住房新科技、绿色环保等多个主…