本节主要内容:
socket编程,使用java实现服务器和客户端之间的相互通信。
在传输层 :TCP/IP
应用层:HTTP、FTP、SMTP、Telnet
IP地址格式:数字型,如:192.168.0.1
常用端口号:http:80 ftp:12 telnet:23
/*
* 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("LAPTOP-QQ7UOKQV");
System.out.println("计算机名:"+address2.getHostName());
System.out.println("IP地址:"+address2.getHostAddress());
//根据ip地址获取iNetaddress实例
InetAddress address3 = InetAddress.getByName("192.168.1.151");
System.out.println("计算机名:"+address3.getHostName());
System.out.println("IP地址:"+address3.getHostAddress());
}
}import java.net.MalformedURLException;
import java.net.URL;
public class Test02 {
public static void main(String[] args) {
try {
//创建一个URL实例
URL imooc = new URL("http://www.imooc.com");
//有已存在的url实例创建一个新的url
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读取页面内容
*/
public class Test03 {
public static void main(String[] args) {
//创建一个url实例
try {
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();
}
}
}具体方法从api文档里面看
以登录界面为例子
/*
* 基于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();
}
}
}服务器端修改
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/*
* 基于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 os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);//包装为打印流
pw.write("欢迎您!");
pw.flush();//调用flush()方法将缓冲输出
//5.关闭资源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}客户端修改
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
/*
* 客户端
*/
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();
}
}
}再来复习一下这个过程
实现服务器与多客户端之间的通信
我们新创建一个服务器线程处理类SeverThread
/*
* 服务器线程处理类
*/
import java.io.*;
import java.net.Socket;
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) {
e.printStackTrace();
} finally {
//5.关闭资源
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();
}
}
}
}修改服务端程序
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/*
* 基于TCP协议的Socket通信,实现用户登录
* 服务器端
*/
public class Server {
public static void main(String[] args) {
try {
//创建一个服务器端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);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}我们先启动server,启动client,再启动一次client
可以看到,两次启动client,其输出均为
server的输出为
并且服务端一直在循环监听
这就实现了多客户端的同时登陆
这时我们继续完善程序,获取客户端的地址和主机名
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());
}package com.sxc;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/*
* 服务器端,实现基于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();
}
}package com.sxc;
/*
* 客户端
*/
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
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.创建DatagranSocket对象
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();
}
}运行服务端,之后运行客户端
如何实现服务器和多客户端之间的通信?使用多线程
其他注意的点
刚才的案例中我们使用的都是字符串数组传输数据,实际应用中我们会使用对象(用户封装成一个user对象)。这个时候要使用对象的传输。
刚才我们服务端和客户端传递的是字符串,如果我们在两端中间要传递文件呢。(涉及到文件读入操作)
参考实现:https://blog.csdn.net/su20145104009/article/details/52843735