IP:定位网络中的不同节点(电子设备:手机,电脑,路由器。。。)
特殊的IP地址:
192.168.0.0~192.168.255.255局域网内部使用
127.0.0.1本地IP
localhost本地域名
IP和 域名:他们之间用过域名解析服务器转换。
端口:区分不同软件
端口号占用两个字节0~65535,同一协议下,端口号不能冲突,设置端口号时尽量越大越好。
预留端口号:8000;
常见端口号:
80:http;
8080:tomcat
1521:Oracle
3306:mysql
InetAddress类 此类表示互联网协议(IP)地址
InetSocketAddress 此类实现 IP 套接字地址(IP 地址 + 端口号)。
- URL:统一资源定位符,区分不同的资源
- 互联网的三大基石: http、html 、url
常用方法:
- String getHostAddress() 返回 IP 地址字符串(以文本表现形式)。
- String getHostName() 获取此 IP 地址的主机名。
- static InetAddress getByName(String host) 在给定主机名的情况下确定主机的 IP 地址。
- InetSocketAddress(InetAddress addr, int port) 根据 IP 地址和端口号创建套接字地址。
- InetSocketAddress(int port) 创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。
- InetSocketAddress(String hostname, int port) 根据主机名和端口号创建套接字地址。
Socket套接字:传输层为应用层开辟的通道(小口子)
- 不同的协议针对于Socket的实现是不同的
- 传输层协议之间的区别:
- tcp: 相当于打电话 基于面向连接的 安全 基于io流传输 占用资源多,开销大,效率低 3次握手:1.请求 2.回应 3.传输
- udp: 相当于写信 非面向连接的 只管发送 不安全 开销小,效率高 大小有限制 一般不超过60k 基于字节数组
- UDP实现Socket编程:
- DatagramSocket:定义发送端和接收端
- DatagramPacket:数据的包裹
udp实现发送端:基本流程
- 1.DatagramSocket 指定端口 定义发送端 DatagramSocket(int port)
- 2.准备数据 ,转为字节数组
- 3.DatagramPacket 打包
- 4.发送 void send(DatagramPacket p) 从此套接字发送数据报包。
- 5.关闭资源
public class UDPSend {
public static void main(String[] args) throws IOException {
System.out.println("---------发送端----------");
//1.定义发送端 DatagramSocket(int port)
DatagramSocket send=new DatagramSocket(8888);
//2.准备数据 ,转为字节数组
String msg="你好就好,要过的没我好...";
byte[] arr=msg.getBytes();
//3.3.DatagramPacket 打包
//DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
//DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)
DatagramPacket packet=new DatagramPacket(arr,0,arr.length,new InetSocketAddress("127.0.0.1", 9999));
//4.发送
send.send(packet);
//5.关闭
send.close();
}
}
UDP实现接收端:基本流程
- 1.DatagramSocket 指定端口号 定义接收端
- 2.准备字节数组,进行打包(用来接收数据,把数据接收到包裹里面的字节数据中)
- 3.接收
- 4.处理数据
- 5.关闭
public class UDPReceive {
public static void main(String[] args) throws IOException {
System.out.println("---------接收端----------");
//1.DatagramSocket 指定端口号 定义接收端
DatagramSocket rec=new DatagramSocket(9999);
//2.准备字节数组,进行打包(用来接收数据,把数据接收到包裹里面的字节数据中)
byte[] arr=new byte[1024*60];
//3.打包
//DatagramPacket(byte[] buf, int offset, int length)
DatagramPacket packet=new DatagramPacket(arr,0,arr.length);
//4.接收
rec.receive(packet); //阻塞式接收
//5.处理数据
/*
* byte[] getData() 返回数据缓冲区。
int getLength() 返回将要发送或接收到的数据的长度。
*/
byte[] newArr=packet.getData();
System.out.println(newArr.length); //字节数组的长度
System.out.println(packet.getLength()); //接到数据的个数
System.out.println(new String(newArr,0,packet.getLength()));
//6.关闭
rec.close();
}
}
tcp实现客户端:基本流程
- 1.定义客户端 Socket 指定服务端的ip 端口
- 2.准备数据
- 3.通过io读写
- 4.关闭
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("---------Client------------");
//1.定义客户端 Socket 指定服务端的ip 端口
Socket client=new Socket("localhost", 8888);
String str="哈哈";
//2.获取输出流 OutputStream getOutputStream() 返回此套接字的输出流。
OutputStream out=new BufferedOutputStream(client.getOutputStream());
//写出
out.write(str.getBytes());
//3.关闭
out.flush();
out.close();
client.close();
}
}
tcp实现服务端:基本流程
- 1.定义服务端 ServerSocket
- 2.阻塞式监听
- 3.通过io读写
- 4.关闭
public class Server {
public static void main(String[] args) throws IOException {
System.out.println("---------Server------------");
//1.定义服务端 ServerSocket
ServerSocket server=new ServerSocket(8888);
//2.Socket accept() 侦听并接受到此套接字的连接。
Socket client=server.accept();
System.out.println("--------一个客户端连接成功---------");
InputStream is=new BufferedInputStream(client.getInputStream());
byte[] car=new byte[1024];
int len=is.read(car);
System.out.println(new String(car,0,len));
//3.关闭
is.close();
client.close();
server.close();
}
}
如果单线程:多个客户端只能做到排队连接
如果想要多个客户端同时连接:多线程,对于服务端而言一个客户端就是一个线程
tcp实现多客户端登录:服务端
- 1.定义服务端 ServerSocket
- 2.阻塞式监听
- 3.通过io读数据
- 4.进行判断
- 5.关闭
public class LoginMulServer {
public static void main(String[] args) throws IOException {
System.out.println("---------Server------------");
//1.定义服务端 ServerSocket
ServerSocket server=new ServerSocket(8989);
//2.Socket accept() 侦听并接受到此套接字的连接。
boolean flag=true;
while(flag){
Socket client=server.accept();
System.out.println("--------一个客户端连接成功---------");
new Thread(new Channel(client)).start();
}
//3.关闭
server.close();
}
//封装一个客户端执行的操作
static class Channel implements Runnable{
Socket client;
DataInputStream is;
DataOutputStream out;
public Channel(Socket client) {
this.client=client;
try {
is=new DataInputStream(client.getInputStream());
out=new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
//读入的功能
public String read(){
String str="";
try {
str=is.readUTF();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
//写出的功能
public void write(String str){
try {
out.writeUTF(str);
} catch (IOException e) {
e.printStackTrace();
}
}
//封装关闭功能
public void close(){
try {
if(out!=null){
out.close();
}
if(is!=null){
is.close();
}
if(client!=null){
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
String str=read();
System.out.println(str);
String uname=null;
String upwd=null;
//数据的处理
String[] keyValue=str.split("&");
for(String s:keyValue){
String[] ss=s.split("=");
if("uname".equals(ss[0])){
uname=ss[1];
}else if("upwd".equals(ss[0])){
upwd=ss[1];
}
}
//如果用户名为 laopei,密码为0523 uname=laopei&upwd=1234
if("laopei".equals(uname) && "1234".equals(upwd)){
write("登录成功");
}else{
write("用户名或密码有误");
}
try {
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
close();
}
}
}