1、TCP套接字编程
ServerSocket(服务端)和Socket(客户端)
1.ServerSocket
java.net.ServerSocket类用于服务器程序获得一个端口,并监听客户端请求。
该类有四个构造器:
构造器 | 用法 |
---|---|
public ServerSocket(int port) throws IOException. | 创建绑定到特定端口的服务器套接字。如果该端口已经被其它应用程序绑定,那么就会发生一个异常。如果端口号设置为0,将会在任何空闲的端口上创建套接字。 |
public ServerSocket(int port, int backlog) throws IOException. | 利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。backlog参数指定可以有多少客户端存在等待队列中。如果队列满了,当客户端试图连接到该端口时,就会接收到一个异常。如果该值为0,就使用本地平台默认的队列大小。 |
public ServerSocket(int port, int backlog, InetAddress address) throws IOException | 与上一个构造器相似,但是用InetAddress参数指定要绑定到的本地IP地址。有多个IP地址的服务器可以用InetAddress来指定用哪个IP地址来接收客户端请求。 |
public ServerSocket() throws IOException | 创建非绑定服务器套接字。在使用该构造器时,用bind()方法来只绑定服务器套接字。 |
ServerSocket类的常用方法如下:
方法 | 用法 |
---|---|
public int getLocalPort() | 返回服务器套接字监听的端口。如果我们给ServerSocket的构造器传入端口号为0,让服务器选择一个端口,那么就要用到这个方法。 |
public Socket accept() throws IOException | 等待要连接的客户端。该方法会阻塞,直到一个客户端连接到指定端口上的服务器,或者假如我们用setSoTimeout()方法设置了超时值,而套接字超过该值了。否则,该方法就无限阻塞下去。 |
public void setSoTimeout(int timeout) | 设置超时值,指定在accept()方法调用期间,服务器套接字等待客户端的时间。 |
public void bind(SocketAddress host, int backlog) | 将套接字绑定到SocketAddress对象中指定的服务器和端口。如果我们使用无参数的构造器实例化一个ServerSocket对象,就要使用该方法。 |
2.Socket
java.net.Socket类代表用于客户端和服务器相互通讯的套接字
Socket类有五个构造器用于将客户端连接到服务器:
构造器 | 用法 |
---|---|
public Socket(String host, int port) throws UnknownHostException, IOException | 试图连接到服务器上指定端口。如果该构造器没有抛出一个异常,那么连接就成功了,而客户端就连接到服务器了。当连接到服务器时,这是最简单的构造器。 |
public Socket(InetAddress host, int port) throws IOException | 与上一个构造器相同,但是主机是通过InetAddress对象描述的。 |
public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException | 连接到指定的主机和端口,并在本地主机上的指定地址和端口上创建一个套接字。当客户端有多个IP地址,或者想让套接字绑定到特定的本地端口上时,通常使用该构造器。 |
public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException | 与前一个构造器相同,但是主机是用InetAddress描述的。 |
public Socket() | 创建一个非连接的套接字。以后可以使用connect()方法将该套接字连接到服务器。 |
当Socket类的构造器返回时,它不仅仅是实例化一个Socket对象。在构造器中,它实际上试图连接到指定的服务器和端口。如果构造器成功返回,客户端就有了一个到服务器的TCP连接。
下面列出了Socket类的一些方法。注意,因为客户端和服务器都有一个Socket对象,所以客户端和服务器都可以调用这些方法。
方法 | 用法 |
---|---|
public void connect(SocketAddress host, int timeout) throws IOException | 将套接字连接到指定主机。本方法只有在使用无参数构造器实例化Socket时才需要。 |
public InetAddress getInetAddress() | 返回该Socket连接到的其它计算机的地址。 |
public int getPort() | 返回套接字绑定到的远程机器上的端口。 |
public int getLocalPort(). | 返回套接字绑定到的本地机器上的端口。 |
public SocketAddress getRemoteSocketAddress() | 返回远程套接字的地址。 |
public InputStream getInputStream() throws IOException | 返回套接字的输入流。该输入流连接到远程套接字的输出流。 |
public OutputStream getOutputStream() throws IOException | 返回套接字的输出流。该输出流连接到远程套接字的输入流。 |
public void close() throws IOException | 关闭套接字,让该Socket对象不再有能力再次连接到任何服务器。 |
使用TCP套接字进行文件传输示例:
客户端
public class Client {
public static void main(String[] args) {
Socket socket = null;
InputStream ins = null;
OutputStream os = null;
BufferedReader inr = null;
try {
// 客户端socket对象
socket = new Socket("127.0.0.1", 9000);
File file = new File("F:\\包\\王.txt");
// 往服务器端写数据
ins = new FileInputStream(file);
os = socket.getOutputStream();
int i = 0;
byte[] b = new byte[1024];
while ((i = ins.read(b)) != -1) {
os.write(b, 0, i);
}
socket.shutdownOutput();
// 获取服务端返回的数据
InputStream in = socket.getInputStream();
int i1 = 0;
byte[] b1 = new byte[1024];
while((i1 = in.read(b1))!= -1) {
if(new String(b1,0,i1).equals(String.valueOf(file.length()))) {
System.out.println("上传成功");
}else {
System.out.println("上传失败");
}
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
ins.close();
os.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
服务端
public class Server {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream ins = null;
OutputStream os1 = null;
BufferedWriter bwos = null;
try {
//服务器端对象
serverSocket = new ServerSocket(9000);
//获取连接服务器端的对象
socket = serverSocket.accept();
File file = new File("F://包//xin//");
if(!file.exists()) {file.mkdirs();}
ins = socket.getInputStream();
os1 = new FileOutputStream(file.getPath()+File.separator+"xxxx.txt");
byte[] b = new byte[1024];
int i = 0;
int sum = 0;
while((i = ins.read(b))!= -1) {
os1.write(b, 0,i);
os1.flush();
sum+=i;
}
//关闭
System.out.println("上传");
socket.shutdownInput();
//返回给客户端
socket.getOutputStream().write(String.valueOf(sum).getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
ins.close();
os1.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
在使用是Socket的时候会遇到SocketException异常
出现SocketException异常的四大原因
错误 | 原因 |
---|---|
java.net.SocketException: Connection refused: connect | 异常发生的原因是或者具有ip地址的机器不能找到,或者该ip存在,但找不到指定的端口进行监听 |
java.net.SocketException: Socket is closed | 异常在客户端和服务器均可能发生。异常的原因是己方主动关闭了连接后(调用了Socket的close方法)再对网络连接进行读写操作 |
java.net.SocketException: (Connection reset或者Connect reset by peer:Socket write error) | 在连接断开后的读和写操作引起的 |
java.net.SocketException: Broken pipe | 异常在客户端和服务器均有可能发生,Connect reset by peer:Socket write error发生后继续写数据 |
2、URL
1.url
一个URL可以分为如下几个部分:
//这里,路径也称为文件名,主机也称为授权。协议包含HTTP、HTTPS、FTP和File
协议://主机:端口/路径?查询字符串#锚点引用
URL类有如下几个构造器用于创建URL:
构造器 | 用法 |
---|---|
public URL(String protocol, String host, int port, String file) throws MalformedURLException | 根据指定 protocol、host、port 号和 file 创建 URL 对象。 |
public URL(String protocol, String host, String file) throws MalformedURLException | 与前一构造器相同,但是用的是指定协议的默认端口。 |
public URL(String url) throws MalformedURLException | 根据给定的字符串创建URL对象。 |
URL类中有很多方法用于访问URL的不同部分,常用的方法如下:
方法 | 用法 |
---|---|
public String getPath() | 获取此URL的路径部分。 |
public String getQuery() | 获取此 URL 的查询部分。 |
public String getAuthority() | 获取此 URL 的授权部分。 |
public int getPort() | 获取此 URL 的端口号。 |
public int getDefaultPort() | 获取与此 URL 关联协议的默认端口号。 |
public String getProtocol() | 获取此 URL 的协议名称。 |
public String getHost() | 获取此 URL 的主机名。 |
public String getFile() | 获取此 URL 的文件名。 |
public String getRef() | 获取此 URL 的锚点。 |
public URLConnection openConnection() throws IOException | 打开一个到该URL的连接,允许客户端与该资源进行通讯。 |
2.URLConnection
使用URL类的openConnection()方法返回一个URLConnection,URLConnection是一个抽象类,其子类代表不同类型的URLConnection
常用的方法:
方法 | 用法 |
---|---|
public void setDoInput(boolean input) | 将此 URLConnection 的 doInput 字段的值设置为指定的值。URL 连接可用于输入和/或输出。如果打算使用 URL 连接进行输入,则将 DoInput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 true,因为客户端通常是从URLConnection中读取。 |
public void setDoOutput(boolean output) | 将此 URLConnection 的 doOutput 字段的值设置为指定的值。如果打算使用 URL 连接进行输出,则将 DoOutput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 false,因为很多URL类型不支持写入数据。 |
public InputStream getInputStream() throws IOException | 返回从资源读取的URLConnection的输入流。 |
public OutputStream getOutputStream() throws IOException | 返回写入到此连接的输出流。返回写入到资源的URLConnection的输出流。 |
public URLgetURL() | 返回此URLConnection对象要连接到的URL。 |
3.URLEncoder
该类只有一个静态方法
//使用特定的编码方案将字符串转换为 application/x-www-form-urlencoded格式。
URLEncoder.encode(String s, String enc)
将String转换为application/x-www-form-urlencoded MIME格式的静态方法
编码字符串时,适用以下规则:
- “ a ”至“ z ”,“ A ”至“ Z ”和“ 0 ”至“ 9 ”保持不变。
- 特殊字符“ . ”,“ - ”,“ * ”和“ _ ”保持不变。
- 空格字符“”被转换为加号“ + ”。
- 所有其他字符都不安全,并且首先使用一些编码方案将其转换为一个或多个字节。 然后每个字节由3个字符串“ %xy ”表示,其中xy是字节的两位十六进制表示。 推荐使用的编码方案是UTF-8。 但是,出于兼容性原因,如果未指定编码,则使用平台的默认编码。
4.URLDecoder
该类只有一个静态方法
//使用特定的编码方案解码 application/x-www-form-urlencoded字符串。
URLDecoder.decode(String s, String enc)
用于从application/x-www-form-urlencoded MIME格式解码字符串的静态方法
在转换中应用以下规则:
- “ a ”至“ z ”,“ A ”至“ Z ”和“ 0 ”至“ 9 ”保持不变。
- 特殊字符“ . ”,“ - ”,“ * ”和“ _ ”保持不变。
- 加号“ + ”被转换为空格字符“”。
- 格式“ %xy ”的序列将被视为表示一个字节,其中xy是8位的两位十六进制表示。 然后,连续包含这些字节序列中的一个或多个的所有子字符串将被编码将导致这些连续字节的字符替换。 可以指定用于解码这些字符的编码方案,或者如果未指定,则将使用平台的默认编码。
Java网络编程代码示例:https://download.youkuaiyun.com/download/qq_39997210/11461141