深圳大学计算机网络实验五:Socket编程

您所在的位置:网站首页 计算机网络编程 深圳大学计算机网络实验五:Socket编程

深圳大学计算机网络实验五:Socket编程

2023-09-11 06:38| 来源: 网络整理| 查看: 265

更好的阅读体验 IP Address 网络编程模型

image-20220403113204888

InetAddress InetAddress类主要是用来得到所指定的网络地址InetAddress类没有直接显式的构造函数。要生成一个InetAddress对象,必须运用一个可用的工厂方法。工厂方法(factory method)仅是一个类中的静态方法返回一个该类实例的约定。这是在一个带有各种参数列表的重载构造函数中完成的,当持有惟一方法名时可使结果更清晰。InetAddress有三个方法可以用来创建InetAddress的实例 static InetAddress getLocalHost( ) throws UnknownHostExceptionstatic InetAddress getByName(String hostName) throws UnknownHostExceptionstatic InetAddress[ ] getAllByName(String hostName) throws UnknownHostException InetAddress类的非静态方法 boolean equals(Object other) 如果对象具有和other相同的Internet地址则返回true。byte[ ] getAddress( ) 返回此InetAddress对象的原始 IP 地址。String getHostAddress( ) 返回与InetAddress对象相关的主机地址的字符串。String getHostName( ) 返回与InetAddress对象相关的主机名的字符串。int hashCode( ) 返回调用对象的散列码。boolean isMulticastAddress( ) 如果Internet地址是一个多播地址则返回true;否则返回false。String toString( ) 返回主机名字符串和IP地址。 URL URL类封装了使用统一资源定位器(Uniform Resource Locator)访问一个WWW上的资源的方法。这个类可以生成一个寻址或指向某个资源的对象。URL类生成的对象指向WWW资源(Web页、文本文件、图形文件、声频片段等等)URL的基本表示方法是:Protocol://hostname:port/resourcename#anchor,即 协议://主机名:端口/资源名#标记 构造方法 public URL (String spec) 通过一个表示URL地址的字符串可以构造一个URL对象。如以下语句:URL urlBase=new URL("http://www. 263.net/"); public URL(URL context, String spec) 通过基URL和相对URL构造一个URL对象。如以下语句:`URL net263=new URL (“http://www.263.net/”);````URL index263=new URL(net263, “index.html”)` public URL(String protocol, String host, String file); URL url=new URL("http", "www.gamelan.com", "/pages/Gamelan.net. html");public URL(String protocol, String host, int port, String file); URL gamelan=new URL("http", "www.gamelan.com", 80, "Pages/Gamelan.network.html"); URL常用方法 public String getProtocol() 获取该URL的协议名。public String getHost() 获取该URL的主机名。public int getPort() 获取该URL的端口号,如果没有设置端口,返回-1。public String getFile() 获取该URL的文件名。public String getQuery() 获取该URL的查询信息。public String getPath() 获取该URL的路径。public String getAuthority() 获取该URL的权限信息。public String getUserInfo() 获得使用者的信息。public String getRef() 获得该URL的引用。 URL类的应用

URL类经常用于下载网络资源,URL通过构造函数(构造函数为URL地址)可以得到一个对象,该对象的openStream()方法可以得到InputStream对象,得到InputStream就可以把网站上的资源下载下来了

下面是一个实例,使用URL类下载某个网站上的一张图片并保存到本地。

import java.net.*; import java.io.*; public class TestURL { public static void main(String aregs[ ])throws Exception { URL url=new URL("http://images.sohu.com/uiue/sohu_logo/beijing2008/sohu.gif"); InputStream in=url.openStream(); FileOutputStream fout=new FileOutputStream(new File("sohu.gif")); int a=0; while(a>-1) { a=in.read(); fout.write(a); } } }

运行成功后,在当前目录生成一个gif图片

URLConnection URL类中的openConnection()方法可生成一个URLConnection对象,URLConnection类的实例可用于读取和写入此URL引用的资源。在网络编程工作中,JAVA的URLConnection是一个常用的类,它提供了一个非常方便的接口,只要提供需要连接的主机的URL地址,使用URL类的openConnection()方法就可以得到一个HttpURLConnection的对象,其中HttpURLConnection类是URLConnection类的子类,然后在此基础上分析HTTP内容,完成相关任务。在这种方式下,使用者不必考虑底层的实现细节,避免了烦琐的Socket类的代码编写,因此比较常用。 URLConnection常用方法 String getHeaderField(String name) 返回指定的头字段的值。InputStream getInputStream() 返回在此打开的连接读取的输入流。String getContentEncoding() 返回content-encoding头字段的值。int getContentLength() 返回content-length头字段的值。String getContentType() 返回content-type头字段的值。long getDate() 返回date头字段的值。 练习

使用InetAddress类的方法获取本地机的名称和IP地址

package com.ipaddress; import java.net.*; public class IPAddress { public static void main(String[] args) { try { InetAddress inetAddress = InetAddress.getLocalHost(); String hostName = inetAddress.getHostName(); String hostAddress = inetAddress.getHostAddress(); System.out.println(hostName); System.out.println(hostAddress); } catch (UnknownHostException e) { e.printStackTrace(); } } }

打印结果:

MacBook-Air.local 192.168.0.101

使用InetAddress类的方法获取网站www.csdn.net的IP地址,如果存在多个IP地址,要求全部返回。

package com.ipaddress; import java.net.*; public class CSDNAddress { public static void main(String[] args) { try { InetAddress[] inetAddresses = InetAddress.getAllByName("www.csdn.net"); for (InetAddress inetAddress: inetAddresses) { String hostName = inetAddress.getHostName(); String hostAddress = inetAddress.getHostAddress(); System.out.println(hostName + " " + hostAddress); } } catch (UnknownHostException e) { e.printStackTrace(); } } }

打印结果

www.csdn.net 39.106.226.142

使用URL类下载深圳大学首页http://www.szu.edu.cn,并统计下载得到网页文件的大小

package com.ipaddress; import java.net.*; import java.io.*; public class SZUurl { public static void main(String[] args) throws Exception { URL url = new URL("http://www.szu.edu.cn"); URLConnection connection = url.openConnection(); int size = connection.getContentLength(); InputStream in = url.openStream(); FileOutputStream fout = new FileOutputStream(new File("szu.html")); int a = 0; while(a > -1) { a = in.read(); fout.write(a); } fout.close(); System.out.println(size + "B"); } }

打印结果

137 B

此时目录结构,可以看到szu.html文件在此目录下

$ tree . ├── Network.iml ├── out │ └── production │ └── Network │ └── com │ └── ipaddress │ ├── CSDNAddress.class │ ├── IPAddress.class │ └── SZUurl.class ├── src │ └── com │ └── ipaddress │ ├── CSDNAddress.java │ ├── IPAddress.java │ └── SZUurl.java └── szu.html 8 directories, 8 files 网络聊天室 套接字(Socket) 用于实现网络上客户端程序和服务器程序之间的连接。套接字负责网络上进程之间的通信客户端程序可以向套接字里写入请求,然后服务器会处理这个请求,并把处理结果通过套接字送回。服务器应用程序一般会侦听一个特定端口,用来等待客户的连接请求,当一个连接请求到达时,客户和服务器会建立一个通信连接,在连接过程中,客户被分配一个本地端口号并与一个Socket连接,客户通过写Socket来通知服务器,再通过读取Socket来获取服务器发送过来的信息。类似地,服务器也获取一个本地端口号,它需要一个新的端口号来侦听原始端口上的其他连接请求。服务器也给它的本地端口连接一个Socket,通过读写它来与客户通信。Socket可以根据通信性质分类,这种性质对于用户是可见的。应用程序一般仅在同一类的套接字之间进行通信。不过只要底层的通信协议允许,不同类型的套接字之间也可以通信。目前可以使用两种套接字,即流套接字和数据报套接字。 流套接字提供了双向的、有序的、无重复的并且无记录边界的数据流服务。TCP是一种流套接字协议数据报套接字支持双向的数据流,但并不保证是可靠、有序、无重复的,也就是说,一个以数据报套接字来接收信息的进程有可能发现信息重复了,或者和发出的顺序不同了。数据报套接字的一个重要特点是它保留了记录边界。UDP即是一种数据报套接字协议。 端口 是一个逻辑概念。每一个服务器都运行在该主机的一个对外开放的端口上。一个主机上可以有多种服务器,也就是有多个端口。程序员可以在创建自己的服务器程序时使用其它端口(即除了系统默认的端口)。端口常以数字编号,作为客户可指定一个端口号,用这个端口号来连接相应的服务器以接收服务。如果把 IP 地址看作电话号码,则端口类似电话的分机号码

cmd > netstat –na 可以查看本机的端口使用情况。

Socket

Socket是网络上运行的程序之间双向通信链路的最后终结点

image-20220403124721918

IP与端口的组合得出一个套接字,可以完全分辨Internet上运行的程序

Socket通信—TCP 一对一的Socket C/S通信 TCP是一种可靠的、基于连接的网络协议,在Internet上大都采用TCP/IP协议进行互联。网络上的两个进程采用C/S模式进行通信。当两台主机准备进行交谈时,都必须建立一个Socket,其中一方作为服务器打开一个Socket并侦听来自网络的连接请求,另一个作为客户,它向网络上的服务器发送请求,通过Socket与服务器传递信息,要建立连接,只需指定主机的IP地址和端口即可。 Socket 工作模式

image-20220403124838800

使用TCP协议的Socket编程

概述

Java提供Socket和ServerSocket类作为标准的TCP套接字编程技术,通过它们实现主机与主机之间(应用程序间)的对话。位于:java.net包中。使用Socket进行C/S程序设计的一般连接过程: Server端Listen(监听)某个端口是否有连接请求,Client端向Server端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。连接建立后,Server端和Client端都可以通过套接字类提供的一些方法与对方通信。

Socket类的构造方法:

public Socket(String host, int port) public Socket(InetAddress address, int port) public Socket(String host, int port, InetAddress localAddr, int localPort) //在指定的机器上的指定端口上运行

上述方法都将抛出例外IOException,程序中需要捕获处理。

Socket的常见方法:

//Socket的输入/输出流管理;抛出例外IOException。 public InputStream getInputStream() public void shutdownInput() public OutputStream getOutputStream() public void shutdownOutput() //关闭Socket public void close() throws IOException //设置/获取Socket数据: public InetAddress getInetAddress() 返回此套接字链接的地址对象 public InetAddress getLocalAddress() 返回此套接字本地的地址对象 public int getPort() 返回此套接字链接地址的端口

上述方法都将抛出例外SocketException,程序中需要捕获处理。

ServerSocket类

构造方法:

public ServerSocket(int port) public ServerSocket(int port, int backlog) //支持指定数目的连接 public ServerSocket(int port, int backlog, InetAddress bindAddr) //在指定的机器上运行

主要方法

public Socket accept():等待客户端的连接 public void close():关闭Socket

设置/获取Socket数据的方法

public InetAddress getInetAddress() public int getLocalPort(), ...

Socket通信程序基本结构都一样,包括以下四个基本步骤:

在客户方和服务器方创建Socket/ServerSocket实例。打开连接到Socket的输入/输出流。利用输入/输出流,按照一定的协议对Socket进行读/写操作。关闭输入/输出流和Socket。

通常,程序员的主要工作是针对所要完成的功能在第3步进行编程,第1、2、4步对所有的通信程序来说几乎都是一样的。

image-20220403125523379

Socket

创建Socket

下面是一个典型的创建客户端Socket的代码:

try { Socket socket=new Socket("127.0.0.1",1432); //127.0.0.1是TCP/IP协议中默认的本机地址 }catch(IOException e){ System.out.println("Error:"+e); }

创建服务器应用程序

用于服务器的类和方法

要创建服务器,你需要创建ServerSocket对象监听客户请求的特定端口。当它认出有效请求,服务器Socket获得客户创建的Socket对象。用这Socket产生位于服务器和客户机之间的通信。

ServerSocket类

ServerSocket类的构造函数带两个参数 :第一个是端口号码 ;第二个参数表示可连接的最大数。ServerSocket类提供如下方法: 监听连接返回地址和本机端口返回表示Socket的串

创建服务器 构造函数的代码给出如下:

try { server = new ServerSocket(1432); //创建一个ServerSocket在端口1432监听客户请求 } catch (Exception e) { System.out.println("can not listen to:" + e); //出错,打印出错信息 } System.out.println("Server started…"); this.start(); //启动线程

监听客户请求

ServerSocket对象通过accept()方法来监听客户的请求,如果接收到客户的请求,则产生一个Socket对象,并继续执行后面的代码;如果没有接收到客户请求,则产生一个错误信息。

Socket socket = null; try { socket = server.accept(); //使用accept()阻塞等待客户请求,有客户 //请求到来则产生一个Socket对象,并继续执行 } catch (Exception e) { System.out.println("can not listen to:" + e); //出错,打印出错信息 }

服务器的输入和输出流 服务器端用到了以下的输入和输出流:

BufferedReader对象用来表示从客户端输入到服务器的流PrintWriter对象表示服务器端输出到客户端的流BufferedReader对象表示从系统标准输入设备输入到服务器端的流。

``java BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream())); //由Socket对象得到输入流,并构造相应的BufferedReader对象 PrintWriter os = new PrintWriter(socket.getOutputStream()); //由Socket对象得到输出流,并构造PrintWriter对象 BufferedReader sin = new BufferedReader(new InputStreamReader(System.in)); //由系统标准输入设备构造BufferedReader对象 { new Server(); }

完整的服务器程序

服务器程序创建了一个BufferedReader对象(is)和一个PrintStream对象(os)。is使用getInputStream()方法检索客户端的输入;os使用getOutputStream()方法使得服务器可以把输出写到客户端。这样一来,就开始了双向通信。当客户连接到服务器时,服务器在标准输出上打印从客户端读入的字符串,然后由BufferedReader对象sin的readline()方法从标准输入读入一字符串,并发送到客户端程序。当有一方输入”bye”时,通信结束。到了结束的时候,服务器中断循环。关闭客户套接字。关闭套接字很重要,如果让连接开着,很快就将耗尽服务器的内存。

ObjectInputStream类

ObjectInputStream类中包含从持久的存储介质中读出类的对象的功能。持久的存储介质可以是磁盘或套接字。

这由ObjectInputStream类的readObject()方法来完成。readObject()方法的语法如下:

FileInputStream fp=new FileInputStream(“data.txt”); ObjectInputStream istream = new ObjectInputStream(fp); Date date = (Date)istream.readObject();

一般步骤

选择创建网络服务器应用程序所需的类和方法。确定用户定义的类,它们的目的,方法。确定用户定义的类中的数据类型和变量。确定服务器的IP地址和端口号。确定查询参数。确定要处理的异常。确定异常的出错信息。 数据报通讯(UDP) 概述

UDP通信是一种无连接的数据报通信。使用该协议,两个程序进行通信时不用建立连接;数据以独立的包为单位发送,包的容量限定在64KB以内;每个数据报需要有完整的收/发地址,可以随时进行收/发数据报,但不保证传送顺序和内容准确;数据报可能会被丢失、延误等。UDP通信是不可靠的通信,但通信速度较快,常常被应用在某些要求实时交互,准确性要求不高,但传输速度要求较高的场合(如视频会议系统等)。

Java中,基于UDP协议实现网络通信的类有三个:

用于表示通信数据的数据报类:DatagramPacket

用于进行端到端通信的类:DatagramSocket

用于广播通信的类:MulticastSocket。

image-20220403131547914

基于UDP通信的基本模式 将数据打包,发往目的地接受别人发来的数据包,察看数据包内容 发送数据包

用DatagramPacket类将数据打包,即创建数据包对象。

DatagramPacket(byte data[], int length, InetAddtress address,int port) Address: 目标主机地址 Port:目标主机端口

如:

byte data[]=“近来好吗”.getByte(); InetAddress address=inetAddress.getByname(www.sina.com.cn); DatagramPacket data_pack=new DatagramPacket(data,data.length,address,980);

注: data_pack常用方法:

Public int getPort();public InetAddress getAddress();public byte[] getData();

用DatagramSocket类的构造方法DatagramSocket()创建一个对象,该对象负责发送数据包。例:

DatagramSocket mail_out=new DatagramSocket();Mail_out.send(data_pack); 接收数据

DatagramSocket mail_in=new DatagramSocket(int port); 注意:mail_in的主要方法:

Receive(DatagramPacket pack) //接收数据包给pack, 例如:DatagramPacket pack=new DatagramPacket(data,length)Mail_in.receive(pack); 练习 练习1

利用Socket类和ServerSocket类编写一个C/S程序,实现C/S通信。

客户端向服务器端发送Time命令,服务器端接受到该字符串后将服务器端当前时间返回给客户端;客户端向服务器端发送Exit命令,服务器端向客户端返回“Bye”后退出。

编写完整程序;一个服务器端程序,一个客户端程序。服务器端和客户端都需要打印出接受到的消息和发出的命令。

下图为运行结果示例

image-20220403132403985

Server.java :

package com.csmode; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.Calendar; public class Server { public static void main(String[] args) { ServerSocket serverSocket = null; Socket socket; DataOutputStream dataOutputStream; DataInputStream dataInputStream; System.out.println("Server Running ... "); String time; String goodbye = "Bye!"; String error = "No such Command!"; try { //在端口号4096创建 serverSocket serverSocket = new ServerSocket(4096); } catch (IOException e) { System.out.println("ServerSocket error"); e.printStackTrace(); } try { assert serverSocket != null; socket = serverSocket.accept(); // 连接成功 dataOutputStream = new DataOutputStream(socket.getOutputStream()); dataOutputStream.writeUTF("服务器启动完毕\n创建客户连接\t\t"); // 标记什么时候退出 boolean flag = true; while(flag) { // 接收客户端发送过来的消息 dataInputStream = new DataInputStream(socket.getInputStream()); String str = dataInputStream.readUTF(); System.out.print(str + " : "); if(str.equals("Time")) { time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime()); dataOutputStream.writeUTF("服务器当前时间为:\t" + time); System.out.println(time); } else if (str.equals("Exit")) { dataOutputStream.writeUTF(goodbye); flag = false; } else { dataOutputStream.writeUTF(error); } } } catch (IOException e) { System.out.println("Socket data IO error"); e.printStackTrace(); } } }

Client.java:

package com.csmode; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.util.Scanner; public class Client { public static void main(String[] args) { try { Socket socket = new Socket("localhost", 4096); // 创建 Socket 管道 DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream()); String string = dataInputStream.readUTF(); System.out.println(string); while(true) { // 输入命令 Scanner input = new Scanner(System.in); String str = input.next(); dataOutputStream.writeUTF(str); // 在服务器端传来的 数据 string = dataInputStream.readUTF(); System.out.println(string); if(str.equals("Exit")) { break; } } } catch (IOException e) { e.printStackTrace(); } } }

先启动Server.java, 再启动Client.java

结果如下:

客户端:

image-20220403182012843

服务器端:

image-20220403182026783

练习2

编写一数据报通信程序,实现简单的聊天功能。

“聊天内容”和“输入文本”分别为当前聊天的历史信息和当前要传送出去的聊天文本。“确定”、“清空”、“退出”三个按钮分别实现发送当前聊天文本、清空当前聊天文本和退出系统的功能。

界面可参考如下格式

image-20220403132507303

PID.java

package com.chattingroom; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; public class PID { // 获取 PID public static int getProcessID() { RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); return Integer.parseInt(runtimeMXBean.getName().split("@")[0]); } }

chat.java

package com.chattingroom; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Font; import java.awt.TextArea; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JTextField; public class chat extends JFrame implements ActionListener, Runnable, KeyListener { private TextArea textArea; private JTextField sendText; private JTextField ip; private JTextField port; private JButton buttonServer; private JButton buttonClient; private JButton send; private JButton exit; private JButton clear; private Socket socket; public void keyReleased(KeyEvent f) { } // 监听键盘输入 public void keyPressed(KeyEvent f) { if (f.getKeyCode() == KeyEvent.VK_ENTER) { PrintWriter printWriter = null; try { printWriter = new PrintWriter(socket.getOutputStream()); } catch (IOException e) { e.printStackTrace(); } String string = sendText.getText(); if (string == null) return; int pid = PID.getProcessID(); String User = ip.getText() + " : " + port.getText(); // 自己发的消息 textArea.append(User + " : " + pid + " says: " + "\n" + string + "\n"); // 对面发来的消息 String string3 = User + " : " + pid + " says: " + "\n" + string; assert printWriter != null; printWriter.println(string3); printWriter.flush(); sendText.setText(""); } } public void keyTyped(KeyEvent f) { } // 轮询 public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); while (true) { String string = br.readLine(); if (string == null) break; textArea.append(string + "\n"); } } catch (Exception e) { e.printStackTrace(); } } public void actionPerformed(ActionEvent e) { if (e.getSource() == buttonServer) { server(); } if (e.getSource() == buttonClient) { client(); } if (e.getSource() == send) { doSend(); } if (e.getSource() == exit) { doExit(); } if (e.getSource() == clear) { doClear(); } } // 作为服务器启动 public void server() { try { ServerSocket server = new ServerSocket(Integer.parseInt(port.getText())); socket = server.accept(); textArea.append("连接服务器成功!\n"); new Thread(this).start(); } catch (Exception e) { textArea.append("服务器启动失败!\n"); } } // 作为客户端启动 public void client() { try { socket = new Socket(ip.getText(), Integer.parseInt(port.getText())); textArea.append("连接服务器成功!\n"); new Thread(this).start(); } catch (Exception e) { textArea.append("连接失败!\n"); } } // 发送消息 public void doSend() { try { PrintWriter printWriter = new PrintWriter(socket.getOutputStream()); String string = sendText.getText(); if (string == null) return; int pid = PID.getProcessID(); String User = ip.getText() + " : " + port.getText(); // 自己发的消息 textArea.append(User + " : " + pid + " says: " + "\n" + string + "\n"); // 对面发来的消息 String string3 = User + " : " + pid + " says: " + "\n" + string; printWriter.println(string3); printWriter.flush(); sendText.setText(""); } catch (Exception e) { textArea.append("发送失败!\n"); } } // 清除聊天 public void doClear() { textArea.setText(""); } // 退出程序 public void doExit() { System.exit(0); } // 连接键 public void addClient(JPanel panel) { buttonClient = new JButton("连接"); buttonClient.setForeground(new Color(250, 131, 46)); buttonClient.setFont(new Font("宋体", Font.BOLD, 14)); panel.add(buttonClient); } // 监听键 public void addServer(JPanel panel) { buttonServer = new JButton("监听"); buttonServer.setForeground(new Color(250, 131, 46)); buttonServer.setFont(new Font("宋体", Font.BOLD, 14)); panel.add(buttonServer); } // 清除键 public void addClear(JPanel panel) { clear = new JButton("清除"); clear.setForeground(new Color(250, 131, 46)); clear.setFont(new Font("宋体", Font.BOLD, 14)); panel.add(clear); } // 退出键 public void addExit(JPanel panel) { exit = new JButton("退出"); exit.setForeground(new Color(250, 131, 46)); exit.setFont(new Font("宋体", Font.BOLD, 14)); panel.add(exit); } // 设置 JPanel public void setPanel(JPanel panel) { panel.setLayout(new BorderLayout()); panel.add(ip, BorderLayout.WEST); panel.setBackground(new Color(245, 161, 102)); sendText = new JTextField(""); panel.add(sendText, BorderLayout.CENTER); send = new JButton("发送"); panel.add(send, BorderLayout.EAST); } // 设置按键监听 public void setListen() { clear.addActionListener(this); exit.addActionListener(this); buttonServer.addActionListener(this); buttonClient.addActionListener(this); send.addActionListener(this); sendText.addKeyListener(this); } public JPanel setJPanel1(Container container) { JPanel panel = new JPanel(); container.add(panel, BorderLayout.NORTH); panel.setBackground(new Color(231, 162, 112)); textArea = new TextArea(); container.add(textArea, BorderLayout.CENTER); return panel; } public JPanel setJPanel2(Container container) { JPanel panel = new JPanel(); container.add(panel, BorderLayout.SOUTH); panel.setBackground(new Color(250, 180, 30)); textArea.setForeground(new Color(250, 131, 46)); return panel; } public void addButton(JPanel panel){ addServer(panel); addClient(panel); addClear(panel); addExit(panel); } // 聊天界面 public chat(String IPAddress, String Port) { this.setTitle("UDP聊天程序"); this.setBounds(200, 200, 500, 500); Container container = this.getContentPane(); JPanel panel1 = setJPanel1(container); JPanel panel2 = setJPanel2(container); ip = new JTextField(IPAddress, 15); port = new JTextField(Port, 4); addButton(panel1); setPanel(panel2); setListen(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }

Run.java

package com.chattingroom; public class Run { public static void main(String[] args) { new chat("127.0.0.1", "8192").setVisible(true); } }

目录结构如下:

$ tree chattingroom chattingroom ├── PID.java ├── Run.java └── chat.java

开启两个程序运行,效果如下:

image-20220403183637735

左端输入123,右端输入456,结果如下:

image-20220403183717239

TCP 文件传输 Java对网络编程的支持 java.net包中的主要的类和可能产生的例外包括: 面向应用层的类: URLURLConnection 面向传输层/IP层的类: TCP协议相关类: SocketServerSocket UDP协议相关类: DatagramPacketDatagramSocketMulticastSocket 表示IP 地址的类: InetAddress 可能产生的异常: BindExceptionConnectExceptionMalformedURLExceptionNoRouteToHostExceptionProtocolExceptionSocketExceptionUnknownHostExceptionUnknownServiceException 练习

利用Socket类和ServerSocket类,编写一个C/S程序,实现网络文件传输。

客户端向服务器端发送请求,服务器端当接受到客户端的请求之后,先向其传输文件名,当客户端接受完毕之后,向客户端传输文件

客户端连上服务器后接收传输文件,并进行改名(文件名可自行定义)存在本地。

编写完整程序;一个服务器端程序,一个客户端程序。服务器端和客户端都需要打印出交互过程。

下图为运行结果示例

服务器端运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V42P3IHL-1648993394649)(https://cdn.jsdelivr.net/gh/Misaka-9982-coder/img_hosting/img/image-20220403132839233.png)]

客服端运行结果:

image-20220403132858447

Server.java

package com.Transmission; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Server implements Runnable { private static final int Port = 4096; private static final int TTL = 20; private final Socket socket; String fileName = "test.txt"; public Server(Socket socket) { super(); this.socket = socket; } public static void server() { try { ServerSocket serverSocket = new ServerSocket(Port); int i = 0; do { i ++ ; Socket socket = serverSocket.accept(); System.out.println("服务器的线程1,启动,与客户端" + i + "连接成功"); new Thread(new Server(socket)).start(); } while (i OutputStream outputStream = null; FileInputStream fileInputStream = null; try { outputStream = socket.getOutputStream(); System.out.println("要传输的文件为: " + fileName); outputStream.write(fileName.getBytes()); System.out.println("开始传输文件"); fileInputStream = new FileInputStream(fileName); int data; while (-1 != (data = fileInputStream.read())) { outputStream.write(data); } System.out.println("文件传输结束"); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fileInputStream != null) fileInputStream.close(); if (outputStream != null) outputStream.close(); this.socket.close(); } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { Server.server(); } }

Client.java

package com.Transmission; import java.io.*; import java.net.InetSocketAddress; import java.net.Socket; public class Client { private static final String SERVERIP = "localhost"; private static final int Port = 4096; private static final int clientPort = 8192; public static void main(String[] args) { byte[] buffer = new byte[2048]; Socket socket = new Socket(); try { socket.connect(new InetSocketAddress(SERVERIP, Port), clientPort); System.out.println("与服务器连接成功"); InputStream inputStream = socket.getInputStream(); int read = inputStream.read(buffer); String fileName = new String(buffer, 0, read); String newName = "test1.txt"; FileOutputStream fileOutputStream = new FileOutputStream(newName); int data; while ((data = inputStream.read()) != -1) { fileOutputStream.write(data); } System.out.println("接收到的文件为:" + fileName); System.out.println("保存为为:" + newName); inputStream.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }

结果:

客户端:

image-20220403214116542

服务器端:

image-20220403214138631

现在文件结构如下:

$ tree . . ├── Network.iml ├── out │ └── production │ └── Network │ └── com │ ├── Transmission │ │ ├── Client.class │ │ └── Server.class │ ├── chattingroom │ │ ├── PID.class │ │ ├── Run.class │ │ └── chat.class │ ├── csmode │ │ ├── Client.class │ │ └── Server.class │ └── ipaddress │ ├── CSDNAddress.class │ ├── IPAddress.class │ └── SZUurl.class ├── src │ └── com │ ├── Transmission │ │ ├── Client.java │ │ └── Server.java │ ├── chattingroom │ │ ├── PID.java │ │ ├── Run.java │ │ └── chat.java │ ├── csmode │ │ ├── Client.java │ │ └── Server.java │ └── ipaddress │ ├── CSDNAddress.java │ ├── IPAddress.java │ └── SZUurl.java ├── szu.html ├── test.txt └── test1.txt 14 directories, 24 files Pythond 的Socket 编程


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3