网络编程一个常用类InetAddress介绍,还有TCP和UDP网络编程
InetAddress类
//本篇主讲InetAddress类
//一个在网络编程常用的类
public class InetAddress_ {
public static void main(String[] args) throws UnknownHostException {
// 获取本机的InetAddress对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);//会输出主机名/IPV4地址
// 根据指定的主机名获取InetAddress对象
InetAddress byName = InetAddress.getByName("LAPTOP-1MJ9VT92");
System.out.println(byName);
// 根据域名返回InetAddress对象
InetAddress host2 = InetAddress.getByName("www.baidu.com");
//域名
System.out.println(host2);//返回的是 域名/百度对应的ip
// 通过InetAdress对象,获取对应的地址
String hostAddress = host2.getHostAddress();
System.out.println(hostAddress);
// 通过InetAdress对象,获取对应的主机名、没有主机名就获取到域名
String hostName = host2.getHostName();
System.out.println(hostName);
}
}
控制台
LAPTOP-1MJ9VT92/192.168.0.101
LAPTOP-1MJ9VT92/192.168.0.101
www.baidu.com/39.156.66.14
39.156.66.14
www.baidu.com
Socket
就是我们通过Socket来获取关于网络的IO流(输入输出流),因为我们不同主机是在网络上传输,运用一个数据通道,而这个Socket就是给我们提供往这个数据通道中写入数据的输出流和接收数据的输入流
注意:Socekt不在文件IO上(就是之前讲过的IO操作文件),而用于网络IO
Socket有两种编程方式1.TCP编程2.UDP编程
TCP编程方式简单介绍
TCP字节流编程
应用案例实现
思路
客户端
package yuan.hsp.net.socket;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
@SuppressWarnings({"all"})
//这里是客户端,发送hello,Server给服务端
public class Cilent {
public static void main(String[] args) throws UnknownHostException, IOException {
// 思路
//连接服务器
//连接成功以后返回Socket对象,赋值给socket
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);//因为我们链接是本机的程序
//所以直接用本机的InetAdress对象即可,如果连接是百度什么的,可以写对应的IPV4,9999的话就是端口号
//连接上以后,通过socket获得和socket对象关联的输出流(就是会输出到服务端)
OutputStream outputStream = socket.getOutputStream();
outputStream.write("Hello,Server".getBytes());//字节流写入
//关闭流和socket
outputStream.close();
socket.close();
System.out.println("客户端退出");
}
}
服务端
package yuan.hsp.net.socket;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import yuan.learn.basic.Multithreading.interrupt_;
@SuppressWarnings({"all"})
//我们网络数据的服务端-本包是TCP字节流编程内容
public class Server {
public static void main(String[] args) throws IOException {
//具体的编程任务可以去看博客-网络编程-TCP字节流编程
//在本机的9999端口监听,要求本机没有其他服务占用9999端口
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端在9999端口监听,等待链接...");
//当没有客户端连接9999端口,程序阻塞等待链接
//如果有客户端链接,会返回一个Socket对象,下面可以直接去看客户端的代码,向服务端请求,然后下面的代码才会运行
Socket accept = serverSocket.accept();
System.out.println("服务端"+accept.getClass());//这句话其实你只运行这个程序,他不会输出,就是因为没客户端连接
//然后我们通过客户端连接本机9999端口,成功的输出了上面那一句话
//现在是接收输入流输入的数据然后输出,可能是通过输入流来读取数据
InputStream inputStream = accept.getInputStream();
//IO读取
byte [] buf = new byte[1024];
int readLen = 0;
while((readLen=inputStream.read(buf))!=-1) {
System.out.println(new String(buf,0,readLen));//String还有这种构造器长见识了,根据读取到内容显示
}
inputStream.close();
accept.close();
serverSocket.close();//比用户端退出多一个步骤
//关于serverSocket和accept(socket对象)区别
//就是第一个可以产生很多个Socket建立,比如说你这个服务端要和多个用户端连接,你不可以只用一个Socket对象
//可以通过serverSocket创建Socket和指定用户连接,就是serverSocket相当于经理,可以派具体的员工
//就建立通讯业务,自己计算负责派人的,而且没有客户的话,员工和这个经理一起关闭,没人要你干什么?
}
}
同时运行两个程序即可建立连接哦
服务端输出
客户端输出
应用案例2
主要讲一个机制
这个其实和那个案例出不了多少我们在原先的代码上改
然后呐
InputStream inputStream = socket.getInputStream();
int readlen=0;
byte [] b =new byte[1024];
while ((readlen=inputStream.read(b))!=-1) {
System.out.println(new String(b,0,readlen));
inputStream.close();
}//加入的就是这几行代码,在客户端,加入位置看我的截图
服务端
OutputStream outputStream = accept.getOutputStream();
outputStream.write("Hello,client".getBytes());
outputStream.close();
然后你运行就会神器的发现
两个程序都卡在了Hello,Server那个程序就不动了,,看运运行窗口那个红色按钮,说明程序还在运行奥
双向连通不成立原因分析
就是需要一个结束标记,你客户端给服务端发hello,server发送他不知道停没停止发送
所以应该在发送完要添加一个结束标记
让客户端读玩hello,server就不要再读了,同样,服务端发送客户端数据也要添加结束标记
不设置的话,就像我们那样,卡住
怎么设置标记呢?
注意的是:只是输出流需要结束标记奥,输入流是看这个结束标记以后就不读取了
socket.shutdownOutput()
客户端加入的地方
服务端加入的地方
这样就能正常运行了
完整的思路解析
TCP字符流编程
和前面要求差不多,结束变为字符流,用到转换流,直接开始写代码
思路
转换+处理流
字符服务端
package yuan.hsp.net.socket;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
@SuppressWarnings({"all"})
//这个的话就是前面字节流变为字符流的改版,要求都一样
//核心思想就是转换流喽
//字符流方便一些
public class zifuServer {
public static void main(String[] args) throws IOException {
//服务端接收
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端在9999端口监听,等待链接...");
Socket accept = serverSocket.accept();
System.out.println("服务端"+accept.getClass());
//先字节流,然后转换流+处理流
InputStream inputStream = accept.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String readLine = bufferedReader.readLine();
System.out.println(readLine);
//接下来是服务端输出
OutputStream outputStream = accept.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello,zifuClient");
bufferedWriter.newLine();//换行代表结束,接收用readLine,就不用accept.shutdownOutput();了
bufferedWriter.flush();//一定要刷新或结束
//关闭外层流即可,而且一般是后打开的流先关闭
bufferedWriter.close();
bufferedReader.close();
accept.close();
serverSocket.close();
}
}
字符输出端
package yuan.hsp.net.socket;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import org.hamcrest.core.StringEndsWith;
@SuppressWarnings({"all"})
public class zifuClient {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));//处理流,里面是转换流
bufferedWriter.write("Hello,zifuServer");
bufferedWriter.newLine();//插入一个换行符,表示原先写入内容结束,就不需要那个字节流的结束标记了,不过接收端要用readLine
bufferedWriter.flush();//字符流需要刷新,才会写入通道
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
System.out.println(bufferedReader.readLine());
//关闭流和socket
bufferedReader.close();
bufferedWriter.close();//关闭这个处理流里面的流也关闭了
socket.close();
System.out.println("客户端退出");
}
}
注意的是,我们newLine()就不用那个socket.shutdownOutput()
newLine()就可以代表结束输入了,不过接收方要用readLine!
然后的话就是
字符流必须flush或者close才会把存储的字符输入到通道中
不像字节流,它是你写几个就输入几个
字符流一定要flush!
netstat指令
netstat指令是网络编程一条常用指令
可以自己在dos里面测试一下
这个显示的内容
协议 本地地址 外部地址 状态
协议名称 IPV4地址:端口号 连接我们的地址 分为正在监听和以及连接
本地地址0.0.0.0和127.0.0.1都代表本机
Listening就是正在监听
Established就是已经连接
注意,外部地址也可以是我们本机的另一个端口,正常做开发就是客户端了
这里用我们之前写的程序演示
出现了8888端口正在监听的状态
还有一条指令 netstat -anb可以具体看到哪个程序在监听这个端口-需要管理员身份启动命令提示符