Java最初是作为网络编程语言出现的,其对网络提供了高度的支持
而在网络编程中使用最多的就是Socket,像QQ,MSN都使用了Socket
相关的技术
Java提供了强大的类,方便网络编程的开发
Socket编程
1. 网络基础知识
2. InetAddress类
3. URL
4. TCP编程
5. UDP编程
两台计算机通过网络进行通信的必备条件:
- IP地址
- 协议
- 端口号
TCP/IP协议
TCP/IP是目前世界上应用最为广泛的协议
是以TCP和IP为基础的不同层次上多个协议的集合
也称:TCP/IP协议族 或 TCP/IP协议栈
- TCP:Transmission Control Protocol 传输控制协议
- IP:Internet Protocol 互联网协议
TCP/IP模型
5. 应用层
- HTTP超文件传输协议
- FTP文件传输协议
- SMTP简单邮件传输协议
- Telnet远程登录服务
4. 传输层
- TCP/IP协议
3. 网络层
2. 数据链路层
1. 物理层
- 网线
- 双绞线
- 网卡
IP地址
为实现网路中不同计算机之间的通信,每台机器都必须有一个唯一的
标识–IP地址
IP地址格式:数字型,如:192.168.0.1
IPv4定义了32位2进制的格式
端口
- 用于区分不同应用程序
- 端口号范围0~65535,其中0~1023为系统所保留
- IP地址和端口号组成了所谓的Socket,Socket是网络上运行
的程序之间双向通信链路的终结点,是TCP和UDP的基础。
- http:80 ftp:21 telnet:23
Java中的网络支持
针对网络通信的不同层次,Java提供的网络功能有四大类:
1. InetAddress:用于标识网络上的硬件资源。
2. URL:统一资源定位符 通过URL可直接读取或写入网络上的数据。
3. Sockets:使用TCP协议实现网络通信的Socket相关类。
4. Datagram:使用UDP协议,将数据保存在数据报中,通
过网络进行通信。
InetAddress类
1. InetAddress类用于标识网络上的硬件资源,表示互联
网协议(IP)地址。
JDK1.8
Class InetAddress
java.lang.Object
java.net.InetAddress
这个类代表一个互联网协议(IP)地址。
Modifier and Type | Method and Description |
---|---|
boolean | equals(Object obj) 将此对象与指定的对象进行比较。 |
byte[] | getAddress() 返回该对象的 InetAddress原IP地址。 |
static InetAddress[] | getAllByName(String host) 给定一个主机的名称,返回其IP地址的数组,基于系统上的配置的名称服务。 |
static InetAddress | getByAddress(byte[] addr) 返回给定的原始IP地址 InetAddress对象。 |
static InetAddress | getByAddress(String host, byte[] addr) 它创造了一个基于所提供的主机名和IP地址。 |
static InetAddress | getByName(String host) 确定主机的IP地址,给定主机名。 |
String | getCanonicalHostName() 获取此IP地址的完全限定的域名。 |
String | getHostAddress() 返回文本表示中的IP地址字符串。 |
String | getHostName() 获取此IP地址的主机名。 |
static InetAddress | getLocalHost() 返回本地主机的地址。 |
static InetAddress | getLoopbackAddress() 返回回送地址。 |
int | hashCode() 返回该IP地址的hash码。 |
boolean | isAnyLocalAddress() 实用程序来检查是否一个通配符解决它。 |
boolean | isLinkLocalAddress() 实用程序检查,如果它是一个链路本地地址。 |
boolean | isLoopbackAddress() 实用程序来检查它是环回地址。 |
boolean | isMCGlobal() 实用程序,检查多播地址是否具有全局范围。 |
boolean | isMCLinkLocal() 实用程序,检查多播地址是否有连接范围。 |
boolean | isMCNodeLocal() 实用程序,检查多播地址是否有节点范围。 |
boolean | isMCOrgLocal() 实用程序,检查多播地址是否有组织范围。 |
boolean | isMCSiteLocal() 实用程序,检查多播地址是否有网站范围。 |
boolean | isMulticastAddress() 实用程序检查,如果它是一个IP多播地址。 |
boolean | isReachable(int timeout) 测试是否该地址是可到达的。 |
boolean | isReachable(NetworkInterface netif, int ttl, int timeout) 测试是否该地址是可到达的。 |
boolean | isSiteLocalAddress() 实用程序检查,如果它是一个站点本地地址。 |
String | toString() 将这个IP地址到一个 String。 |
/*
* InetAddress类
*/
public class Test01 {
public static void main(String[] args) throws UnknownHostException {
// 获取本机的InetAddress实例
InetAddress address = InetAddress.getLocalHost();
System.out.println("计算名:" + address.getHostName());
System.out.println("IP地址:" + address.getHostAddress());
byte[] bytes = address.getAddress();// 获取字节数组形式的IP地址
System.out.println("字节数组形式的IP:" + Arrays.toString(bytes));
System.out.println(address);// 直接输出InetAddress对象
// 根据机器名获取InetAddress实例
InetAddress address2 = InetAddress.getByName("Sc-201411281008");
System.out.println("计算名:" + address2.getHostName());
System.out.println("IP地址:" + address2.getHostAddress());
}
}
URL
1. URL(Uniform Resource Locator)统一资源定位符,表示Internet上某一资源的地址。
2. URL由两部分组成:协议名称和资源名称,中间用冒号隔开。
- http://www.imooc.com
- 协议名称:http
- 资源名称:www.imooc.com
3. 在java.net包中,提供了URL类来表示URL。
Class URL
java.lang.Object
java.net.URL
类 URL代表统一资源定位符,指向“万维网上的资源”。一个资源可以是简单的作为一个文件或一个目录,或者它可以是一个更复杂的对象的参考,如查询到数据库或搜索引擎。
构造方法 | Constructor and Description |
---|---|
URL(String spec) | 创建于 String表示 URL对象。 |
URL(String protocol, String host, int port, String file) | 创建从指定的 protocol, host,一 URL对象 port数,和 file。 |
URL(String protocol, String host, int port, String file, URLStreamHandler handler) | 创建从指定的 protocol, host, port数, file一 URL对象,和 handler。 |
URL(String protocol, String host, String file) | 创建一个URL指定的 protocol名字, host名字,和 file名称。 |
URL(URL context, String spec) | 通过在指定的上下文中解析给定的规范,创建一个网址。 |
URL(URL context, String spec, URLStreamHandler handler) | 通过在指定的上下文中解析给定的规范与指定的处理程序创建一个链接。 |
Modifier and Type | Method and Description |
---|---|
boolean | equals(Object obj) 将此网址与另一个对象进行比较。 |
String | getAuthority() 得到这 URL权威部分。 |
Object | getContent() 获取此网址的内容。 |
Object | getContent(类[] classes) 获取此网址的内容。 |
int | getDefaultPort() 得到这个 URL相关协议的默认端口号。 |
String | getFile() 得到这 URL文件名。 |
String | getHost() 得到这 URL主机名称,如适用。 |
String | getPath() 得到这 URL路径的一部分。 |
int | getPort() 得到这 URL端口号。 |
String | getProtocol() 得到这 URL协议名称。 |
String | getQuery() 得到这 URL查询的一部分。 |
String | getRef() 得到锚(也被称为“参考”)这 URL。 |
String | getUserInfo() 得到这 URL用户信息部分。 |
int | hashCode() 创建一个适用于哈希表索引的整数。 |
URLConnection | openConnection() 返回一个 URLConnection实例表示的远程对象的连接被称为 URL。 |
URLConnection | openConnection(Proxy proxy) 同 openConnection(),除了连接将通过指定的代理进行;协议处理程序不支持proxing将忽略代理参数,使正常的连接。 |
InputStream | openStream() 打开一个连接到这 URL和返回的连接阅读 InputStream。 |
boolean | sameFile(URL other) 比较两个网址,不包括片段组件。 |
static void | setURLStreamHandlerFactory(URLStreamHandlerFactory fac) 设置应用程序的 URLStreamHandlerFactory。 |
String | toExternalForm() 构建该 URL字符串表示形式。 |
String | toString() 构建该 URL字符串表示形式。 |
URI | toURI() 返回一个 URI相当于这个URL。 |
/*
* URL常用方法
*/
public class Test02 {
public static void main(String[] args) {
try {
//创建一个URL实例
URL imooc=new URL("http://www.imooc.com");
//?后面表示参数,#后面表示锚点
URL url=new URL(imooc, "/index.html?username=tom#test");
System.out.println("协议:"+url.getProtocol());
System.out.println("主机:"+url.getHost());
//如果未指定端口号,则使用默认的端口号,此时getPort()方法返回值为-1
System.out.println("端口:"+url.getPort());
System.out.println("文件路径:"+url.getPath());
System.out.println("文件名:"+url.getFile());
System.out.println("相对路径:"+url.getRef());
System.out.println("查询字符串:"+url.getQuery());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
使用URL读取网页内容
1. 通过URL对象的openStream()方法可以得到指定资源的
输入流。
2. 通过输入流可以读取、访问网络上的数据。
/*
* 使用URL读取网页内容
*/
public class Test03 {
public static void main(String[] args) {
try {
//创建一个URL实例
URL url = new URL("http://www.baidu.com");
//通过URL的openStream方法获取URL对象所表示的资源的字节输入流
InputStream is = url.openStream();
//将字节输入流转换为字符输入流
InputStreamReader isr = new InputStreamReader(is, "utf-8");
//为字符输入流添加缓冲
BufferedReader br = new BufferedReader(isr);
String data = br.readLine();//读取数据
while (data != null) {//循环读取数据
System.out.println(data);//输出数据
data = br.readLine();
}
br.close();
isr.close();
is.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Socket通信
TCP协议是面向连接、可靠的、有序的,以字节流的方式发送数据
基于TCP协议实现的网络通信的类
- 客户端的Socket类
- 服务端的ServerSocket类
Socket通信模型
1. 建立连接
- Server
- 建立服务端侦听socket
- 等待并接收连接请求
- 接收请求后创建socket
- Client
- 创建连接socket向服务端发送请求
2. 开始通信
- Server
- InputStream
- OutputStream
- Client
- OutputStream
- InputStream
3. 结束通信
- Server
- 关闭socket及相关资源
- Client
- 关闭socket及相关资源
Socket通信实现步骤
1. 创建ServerSocket和Socket
2. 打开连接到Socket的输入/输出流
3. 按照协议对Socket进行读/写操作
4. 关闭输入输出流、关闭Socket
Class ServerSocket
java.lang.Object
java.net.ServerSocket
这个类实现了服务器套接字。服务器套接字等待来自网络的请求。它基于该请求执行某些操作,然后可能向请求者返回结果。
构造方法 | Constructor and Description |
---|---|
ServerSocket() | 创建一个绑定服务器套接字。 |
ServerSocket(int port) | 创建一个服务器套接字,绑定到指定的端口。 |
ServerSocket(int port, int backlog) | 创建一个服务器套接字,并将其绑定到指定的本地端口号,并使用指定的积压。 |
ServerSocket(int port, int backlog, InetAddress bindAddr) | 用指定的端口创建一个服务器,听积压,和本地IP地址绑定到。 |
Modifier and Type | Method and Description |
---|---|
Socket | accept() 监听要对这个套接字作出的连接并接受它。 |
void | bind(SocketAddress endpoint) ServerSocket绑定到一个特定的地址(IP地址和端口号)。 |
void | bind(SocketAddress endpoint, int backlog) ServerSocket绑定到一个特定的地址(IP地址和端口号)。 |
void | close() 关闭这个套接字。 |
ServerSocketChannel | getChannel() 返回与此套接字关联的独特的 ServerSocketChannel对象,如果任何。 |
InetAddress | getInetAddress() 返回此服务器套接字的本地地址。 |
int | getLocalPort() 返回此套接字正在侦听的端口号。 |
SocketAddress | getLocalSocketAddress() 返回此套接字绑定到的端点的地址。 |
int | getReceiveBufferSize() 得到这个 ServerSocket的 SO_RCVBUF期权的价值,即该缓冲区的大小,将用于接受来自这 ServerSocket插座。 |
boolean | getReuseAddress() 如果 SO_REUSEADDR启用。 |
int | getSoTimeout() 检索设置 SO_TIMEOUT。 |
protected void | implAccept(Socket s) 子类使用此方法重载ServerSocket()返回自己的子类的插座。 |
boolean | isBound() 返回的ServerSocket绑定状态。 |
boolean | isClosed() 返回的ServerSocket关闭状态。 |
void | setPerformancePreferences(int connectionTime, int latency, int bandwidth) 设置此ServerSocket性能偏好。 |
void | setReceiveBufferSize(int size) 设置一个默认值为提出接受这 ServerSocket插座 SO_RCVBUF选项。 |
void | setReuseAddress(boolean on) 启用/禁用 SO_REUSEADDR套接字选项。 |
static void | setSocketFactory(SocketImplFactory fac) 设置服务器套接字实现工厂为应用程序。 |
void | setSoTimeout(int timeout) 启用/禁用 SO_TIMEOUT以指定的超时时间,以毫秒为单位。 |
String | toString() 返回此套接字作为 String实现的地址与端口。 |
Class Socket
java.lang.Object
java.net.Socket
这个类实现了客户端套接字(也被称为“套接字”)。套接字是两台机器之间的通信的一个端点。
构造方法 | Constructor and Description |
---|---|
Socket() | 创建一个连接的套接字,与socketimpl系统默认的类型。 |
Socket(InetAddress address, int port) | 创建一个流套接字,并将其与指定的IP地址中的指定端口号连接起来。 |
Socket(InetAddress host, int port, boolean stream) | 过时的。 使用UDP传输DatagramSocket。 |
Socket(InetAddress address, int port, InetAddress localAddr, int localPort) | 创建一个套接字,并将其与指定的远程端口上的指定的远程地址连接起来。 |
Socket(Proxy proxy) | 创建一个连接的套接字类型,指定代理,如果有,应该使用无论任何其他设置。 |
Socket(SocketImpl impl) | 创建一个用户指定的socketimpl连接插座。 |
Socket(String host, int port) | 创建一个流套接字,并将其与指定的主机上的指定端口号连接起来。 |
Socket(String host, int port, boolean stream) | 过时的。 使用UDP传输DatagramSocket。 |
Socket(String host, int port, InetAddress localAddr, int localPort) | 创建一个套接字,并将其连接到指定的远程端口上的指定的远程主机上。 |
Modifier and Type | Method and Description |
---|---|
void | bind(SocketAddress bindpoint) 将套接字绑定到本地地址。 |
void | close() 关闭这个套接字。 |
void | connect(SocketAddress endpoint) 将此套接字连接到服务器。 |
void | connect(SocketAddress endpoint, int timeout) 将此套接字与指定的超时值连接到服务器。 |
SocketChannel | getChannel() 返回与此套接字关联的独特的 SocketChannel对象,如果任何。 |
InetAddress | getInetAddress() 返回套接字连接的地址。 |
InputStream | getInputStream() 返回此套接字的输入流。 |
boolean | getKeepAlive() 如果 SO_KEEPALIVE启用。 |
InetAddress | getLocalAddress() 获取绑定的套接字的本地地址。 |
int | getLocalPort() 返回此套接字绑定的本地端口号。 |
SocketAddress | getLocalSocketAddress() 返回此套接字绑定到的端点的地址。 |
boolean | getOOBInline() 如果 SO_OOBINLINE启用。 |
OutputStream | getOutputStream() 返回此套接字的输出流。 |
int | getPort() 返回此套接字连接的远程端口号。 |
int | getReceiveBufferSize() 得到这个 Socket的 SO_RCVBUF选项的值,是由平台用于该 Socket输入缓冲区的大小。 |
SocketAddress | getRemoteSocketAddress() 返回此套接字连接的端点的地址,或如果它是无关的 null。 |
boolean | getReuseAddress() 如果 SO_REUSEADDR启用。 |
int | getSendBufferSize() 得到这个 Socket的 SO_SNDBUF期权价值,即缓冲区的大小由平台用于输出在这 Socket。 |
int | getSoLinger() 返回设置 SO_LINGER。 |
int | getSoTimeout() 返回设置 SO_TIMEOUT。 |
boolean | getTcpNoDelay() 如果 TCP_NODELAY启用。 |
int | getTrafficClass() 获取从这个套接字发送的数据包的IP头中的业务类或服务类型 |
boolean | isBound() 返回套接字的绑定状态。 |
boolean | isClosed() 返回套接字的关闭状态。 |
boolean | isConnected() 返回套接字的连接状态。 |
boolean | isInputShutdown() 返回套接字连接的读半是否关闭。 |
boolean | isOutputShutdown() 返回套接字连接的写是否关闭的是否关闭。 |
void | sendUrgentData(int data) 在套接字上发送一个字节的紧急数据。 |
void | setKeepAlive(boolean on) 启用/禁用 SO_KEEPALIVE。 |
void | setOOBInline(boolean on) 启用/禁用 SO_OOBINLINE(TCP紧急数据收据)默认情况下,此选项是禁用TCP套接字上接收紧急数据是默默丢弃。 |
void | setPerformancePreferences(int connectionTime, int latency, int bandwidth) 设置此套接字的性能首选项。 |
void | setReceiveBufferSize(int size) 集 SO_RCVBUF选项,这 Socket指定值。 |
void | setReuseAddress(boolean on) 启用/禁用 SO_REUSEADDR套接字选项。 |
void | setSendBufferSize(int size) 设置这个 Socket指定值的 SO_SNDBUF选项。 |
static void | setSocketImplFactory(SocketImplFactory fac) 设置客户端套接字实现工厂的应用程序。 |
void | setSoLinger(boolean on, int linger) 启用/禁用 SO_LINGER与指定的逗留的时间秒。 |
void | setSoTimeout(int timeout) 启用/禁用 SO_TIMEOUT以指定的超时时间,以毫秒为单位。 |
void | setTcpNoDelay(boolean on) 启用/禁用 TCP_NODELAY(禁用/启用Nagle的算法)。 |
void | setTrafficClass(int tc) 集交通类或从该套接字发送数据包的IP报头字节型服务。 |
void | shutdownInput() 将此套接字的输入流放在“流结束”中。 |
void | shutdownOutput() 禁用此套接字的输出流。 |
String | toString() 将这一 String插座。 |
服务器端
客户端
/**
* 基于TCP协议的socket通信,实现用户登录
* 服务器端
*/
public class Server {
public static void main(String[] args) {
try {
//1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口
ServerSocket serverSocket = new ServerSocket(8888);
//2.调用accept()方法开始监听,等待客户端 的连接
System.out.println("***服务器即将启动,等待客户端的连接***");
Socket socket = serverSocket.accept();
//3.获取输入流,并读取客户端信息
InputStream is = socket.getInputStream();//字节输入流
InputStreamReader isr = new InputStreamReader(is);//将字节输入流转换为字符流
BufferedReader br = new BufferedReader(isr);//为输入流添加缓冲
String info = null;
while((info=br.readLine())!=null) {//循环读取客户端的信息
System.out.println("我是服务器,客户端说:"+info);
}
socket.shutdownInput();//关闭输入流
//4.关闭资源
br.close();
isr.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
try {
//1.创建客户端Socket,指定服务器端地址和端口
Socket socket = new Socket("localhost",8888);
//2.获取输出流,向服务器端发送信息
OutputStream os = socket.getOutputStream();//字节输出流
PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
pw.write("用户名:admin;密码:123");
pw.flush();
socket.shutdownOutput();//关闭输出流
//3.关闭资源
pw.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 基于TCP协议的socket通信,实现用户登录
* 服务器端
*/
public class Server {
public static void main(String[] args) {
try {
//1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口
ServerSocket serverSocket = new ServerSocket(8888);
//2.调用accept()方法开始监听,等待客户端 的连接
System.out.println("***服务器即将启动,等待客户端的连接***");
Socket socket = serverSocket.accept();
//3.获取输入流,并读取客户端信息
InputStream is = socket.getInputStream();//字节输入流
InputStreamReader isr = new InputStreamReader(is);//将字节输入流转换为字符流
BufferedReader br = new BufferedReader(isr);//为输入流添加缓冲
String info = null;
while((info=br.readLine())!=null) {//循环读取客户端的信息
System.out.println("我是服务器,客户端说:"+info);
}
socket.shutdownInput();//关闭输入流
//4.获取输出流,响应客户端请求
OutputStream op = socket.getOutputStream();
PrintWriter pw = new PrintWriter(op);//包装为打印流
pw.write("欢迎您!");
pw.flush();
//5.关闭资源
pw.close();
op.close();
br.close();
isr.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
try {
//1.创建客户端Socket,指定服务器端地址和端口
Socket socket = new Socket("localhost",8888);
//2.获取输出流,向服务器端发送信息
OutputStream os = socket.getOutputStream();//字节输出流
PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
pw.write("用户名:admin;密码:123");
pw.flush();
socket.shutdownOutput();//关闭输出流
//3.获取输入流,并读取服务器的响应信息
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info = null;
while((info = br.readLine()) != null) {
System.out.println("我是客户端,服务器端说:"+info);
}
//4.关闭资源
br.close();
is.close();
pw.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 服务器线程处理类
*/
public class ServerThread extends Thread {
// 和本线程相关的Socket
Socket socket = null;
public ServerThread(Socket socket) {
this.socket = socket;
}
//线程执行的操作,响应客户端的请求
public void run(){
InputStream is=null;
InputStreamReader isr=null;
BufferedReader br=null;
OutputStream os=null;
PrintWriter pw=null;
try {
//获取输入流,并读取客户端信息
is = socket.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String info=null;
while((info=br.readLine())!=null){//循环读取客户端的信息
System.out.println("我是服务器,客户端说:"+info);
}
socket.shutdownInput();//关闭输入流
//获取输出流,响应客户端的请求
os = socket.getOutputStream();
pw = new PrintWriter(os);
pw.write("欢迎您!");
pw.flush();//调用flush()方法将缓冲输出
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//关闭资源
try {
if(pw!=null)
pw.close();
if(os!=null)
os.close();
if(br!=null)
br.close();
if(isr!=null)
isr.close();
if(is!=null)
is.close();
if(socket!=null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
* 基于TCP协议的Socket通信,实现用户登陆
* 服务器端
*/
public class Server {
public static void main(String[] args) {
try {
//1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
ServerSocket serverSocket=new ServerSocket(8888);
Socket socket=null;
//记录客户端的数量
int count=0;
System.out.println("***服务器即将启动,等待客户端的连接***");
//循环监听等待客户端的连接
while(true){
//调用accept()方法开始监听,等待客户端的连接
socket=serverSocket.accept();
//创建一个新的线程
ServerThread serverThread=new ServerThread(socket);
//启动线程
serverThread.start();
count++;//统计客户端的数量
System.out.println("客户端的数量:"+count);
InetAddress address=socket.getInetAddress();
System.out.println("当前客户端的IP:"+address.getHostAddress());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 客户端
*/
public class Client {
public static void main(String[] args) {
try {
//1.创建客户端Socket,指定服务器地址和端口
Socket socket=new Socket("localhost", 8888);
//2.获取输出流,向服务器端发送信息
OutputStream os=socket.getOutputStream();//字节输出流
PrintWriter pw=new PrintWriter(os);//将输出流包装为打印流
pw.write("用户名:admin;密码:123");
pw.flush();
socket.shutdownOutput();//关闭输出流
//3.获取输入流,并读取服务器端的响应信息
InputStream is=socket.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String info=null;
while((info=br.readLine())!=null){
System.out.println("我是客户端,服务器说:"+info);
}
//4.关闭资源
br.close();
is.close();
pw.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
UDP编程
- UDP协议(用户数据报协议)是无连接的、不可靠的,无序的
- UDP协议以数据报作为数据传输的载体
- 进行数据传输时,首先需要将要传输的数据定义成
数据报(Datagram),在数据报中指明数据所要达到的
Socket(主机地址和端口号),然后在将数据报发送出去
相关操作类
- DatagramPacket:表示数据报包
- DatagramSocket:进行端到端通信的类
Class DatagramPacket
java.lang.Object
java.net.DatagramPacket
这类表示一个数据报包。
构造方法 | Constructor and Description |
---|---|
DatagramPacket(byte[] buf, int length) | 接收数据包长度 length DatagramPacket构建。 |
DatagramPacket(byte[] buf, int length, InetAddress address, int port) | 指定主机上的指定端口发送数据包的长度 length数据报包结构。 |
DatagramPacket(byte[] buf, int offset, int length) | 接收数据包长度 length DatagramPacket结构,指定一个偏移量到缓冲区。 |
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) | 发送有偏置 ioffsetto指定端口号指定主机上的数据包长度 length数据报包结构。 |
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) | 发送有偏置 ioffsetto指定端口号指定主机上的数据包长度 length数据报包结构。 |
DatagramPacket(byte[] buf, int length, SocketAddress address) | 指定主机上的指定端口发送数据包的长度 length数据报包结构。 |
Modifier and Type | Method and Description |
---|---|
InetAddress | getAddress() 返回的IP地址的机器,这个数据包被发送或从收到的数据报。 |
byte[] | getData() 返回数据缓冲区。 |
int | getLength() 返回要发送的数据的长度或收到的数据的长度。 |
int | getOffset() 返回所要发送的数据的偏移量或所接收的数据的偏移量。 |
int | getPort() 返回远端端口号,这个数据包被发送或从收到的数据报。 |
SocketAddress | getSocketAddress() 获取SocketAddress(通常是IP地址+端口号)的远程主机,数据包被发送到或来自。 |
void | setAddress(InetAddress iaddr) 设置本机的IP地址,这个数据包被发送。 |
void | setData(byte[] buf) 为这个数据包设置数据缓冲区。 |
void | setData(byte[] buf, int offset, int length) 为这个数据包设置数据缓冲区。 |
void | setLength(int length) 为这个数据包设置长度。 |
void | setPort(int iport) 设置远端端口号,这个数据包被发送。 |
void | setSocketAddress(SocketAddress address) 集SocketAddress(通常是IP地址+端口号)的远程主机的数据报发送。 |
Class DatagramSocket
java.lang.Object
java.net.DatagramSocket
这类代表一个发送和接收数据包的插座。
构造方法 | Modifier Constructor and Description |
---|---|
DatagramSocket() | 构建一个数据报套接字绑定到本地主机的任何可用的端口。 |
DatagramSocket(DatagramSocketImpl impl) | 创建一个绑定的数据报套接字与指定的datagramsocketimpl。 |
DatagramSocket(int port) | 构建一个数据报套接字绑定到本地主机的指定端口。 |
DatagramSocket(int port, InetAddress laddr) | 创建一个数据报套接字,绑定到指定的本地地址。 |
DatagramSocket(SocketAddress bindaddr) | 创建一个数据报套接字,绑定到指定的本地套接字地址。 |
Modifier and Type | Method and Description |
---|---|
void | bind(SocketAddress addr) 结合这个DatagramSocket到特定的地址和端口。 |
void | close() 关闭该数据报套接字。 |
void | connect(InetAddress address, int port) 将套接字连接到这个套接字的远程地址。 |
void | connect(SocketAddress addr) 将此套接字连接到远程套接字地址(IP地址+端口号)。 |
void | disconnect() 断开插座。 |
boolean | getBroadcast() 如果so_broadcast启用。 |
DatagramChannel | getChannel() 返回与此数据报套接字相关的独特的 DatagramChannel对象,如果任何。 |
InetAddress | getInetAddress() 返回此套接字连接的地址。 |
InetAddress | getLocalAddress() 获取绑定的套接字的本地地址。 |
int | getLocalPort() 返回此套接字绑定的本地主机上的端口号。 |
SocketAddress | getLocalSocketAddress() 返回此套接字绑定到的端点的地址。 |
int | getPort() 返回此套接字连接的端口号。 |
int | getReceiveBufferSize() 得到这个 DatagramSocket的so_rcvbuf期权价值,即通过平台用于该 DatagramSocket输入缓冲区的大小。 |
SocketAddress | getRemoteSocketAddress() 返回此套接字连接的端点的地址,或如果它是无关的 null。 |
boolean | getReuseAddress() 如果so_reuseaddr启用。 |
int | getSendBufferSize() 得到这个 DatagramSocket的so_sndbuf期权价值,即缓冲区的大小由平台用于输出在这 DatagramSocket。 |
int | getSoTimeout() 检索设置so_timeout。 |
int | getTrafficClass() 获取交通类或类型的服务在IP数据报头的DatagramSocket发送的数据包。 |
boolean | isBound() 返回套接字的绑定状态。 |
boolean | isClosed() 返回套接字是否关闭或不关闭的。 |
boolean | isConnected() 返回套接字的连接状态。 |
void | receive(DatagramPacket p) 接收数据报包从这个插座。 |
void | send(DatagramPacket p) 从这个套接字发送数据报包。 |
void | setBroadcast(boolean on) 启用/禁用so_broadcast。 |
static void | setDatagramSocketImplFactory(DatagramSocketImplFactory fac) 集的数据报套接字实现工厂的应用。 |
void | setReceiveBufferSize(int size) 集so_rcvbuf选项,这 DatagramSocket指定值。 |
void | setReuseAddress(boolean on) 启用/禁用so_reuseaddr套接字选项。 |
void | setSendBufferSize(int size) 集so_sndbuf选项,这 DatagramSocket指定值。 |
void | setSoTimeout(int timeout) 启用/禁用so_timeout以指定的超时时间,以毫秒为单位。 |
void | setTrafficClass(int tc) 集交通类或从这个DatagramSocket发送数据报的IP数据报头字节型服务。 |
服务端实现步骤
客户端实现步骤
/*
* 服务器端,实现基于UDP的用户登录
*/
public class UDPServer {
public static void main(String[] args) throws IOException {
//1.创建服务端DatagramSocket,指定端口
DatagramSocket socket = new DatagramSocket(8800);
//2.创建数据报,用于接收客户端发送的数据
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data,data.length);
//3.接收客户端发送的数据
socket.receive(packet);//此方法在接收数据报之前会一直阻塞
//4.读取数据
String info = new String(data,0,packet.getLength());
System.out.println("我是服务器,客户端说:"+info);
}
}
/*
* 客户端
*/
public class UDPClient0 {
public static void main(String[] args) throws IOException {
//1.定义服务器的地址、端口号、数据
InetAddress address = InetAddress.getByName("localhost");
int port = 8800;
byte[] data = "用户名:admin;密码:123".getBytes();
//2.创建数据报,包含发送的数据信息
DatagramPacket packet = new DatagramPacket(data, data.length,address,port);
//3.创建DatagramSocket对象
DatagramSocket socket = new DatagramSocket();
//4.向服务器端发送数据报
socket.send(packet);
}
}
/*
* 服务器端,实现基于UDP的用户登陆
*/
public class UDPServer {
public static void main(String[] args) throws IOException {
/*
* 接收客户端发送的数据
*/
//1.创建服务器端DatagramSocket,指定端口
DatagramSocket socket=new DatagramSocket(8800);
//2.创建数据报,用于接收客户端发送的数据
byte[] data =new byte[1024];//创建字节数组,指定接收的数据包的大小
DatagramPacket packet=new DatagramPacket(data, data.length);
//3.接收客户端发送的数据
System.out.println("****服务器端已经启动,等待客户端发送数据");
socket.receive(packet);//此方法在接收到数据报之前会一直阻塞
//4.读取数据
String info=new String(data, 0, packet.getLength());
System.out.println("我是服务器,客户端说:"+info);
/*
* 向客户端响应数据
*/
//1.定义客户端的地址、端口号、数据
InetAddress address=packet.getAddress();
int port=packet.getPort();
byte[] data2="欢迎您!".getBytes();
//2.创建数据报,包含响应的数据信息
DatagramPacket packet2=new DatagramPacket(data2, data2.length, address, port);
//3.响应客户端
socket.send(packet2);
//4.关闭资源
socket.close();
}
}
/*
* 客户端
*/
public class UDPClient {
public static void main(String[] args) throws IOException {
/*
* 向服务器端发送数据
*/
//1.定义服务器的地址、端口号、数据
InetAddress address=InetAddress.getByName("localhost");
int port=8800;
byte[] data="用户名:admin;密码:123".getBytes();
//2.创建数据报,包含发送的数据信息
DatagramPacket packet=new DatagramPacket(data, data.length, address, port);
//3.创建DatagramSocket对象
DatagramSocket socket=new DatagramSocket();
//4.向服务器端发送数据报
socket.send(packet);
/*
* 接收服务器端响应的数据
*/
//1.创建数据报,用于接收服务器端响应的数据
byte[] data2=new byte[1024];
DatagramPacket packet2=new DatagramPacket(data2, data2.length);
//2.接收服务器响应的数据
socket.receive(packet2);
//3.读取数据
String reply=new String(data2, 0, packet2.getLength());
System.out.println("我是客户端,服务器说:"+reply);
//4.关闭资源
socket.close();
}
}
重点
- Socket通信原理
- 基于TCP的Socket通信
Java Socket应用—通信是这样练成的视频地址