网络编程三要素
1 IP地址:InetAddress: 网络中设备的标识,不易记忆,可用主机名
IP地址 = 网络地址+主机地址
A类IP地址:第一段号码为网络地址,剩下的三段号码为本地计算机的号码
1.0.0.1—127.255.255.254
(1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址)
(2)127.X.X.X是保留地址,用做循环测试用的。
B类IP地址:前二段号码为网络地址,剩下的二段号码为本地计算机的号码
128.0.0.1—191.255.255.254 172.16.0.0—172.31.255.255是私有地址。
C类IP地址:前三段号码为网络地址,剩下的一段号码为本地计算机的号码
192.0.0.1—223.255.255.254 192.168.x.X是私有地址
2 端口号: 用于标识进程的逻辑地址,不同进程的标识
物理端口 网卡口
逻辑端口 我们指的就是逻辑端口
a:每个网络程序都会有一个逻辑端口
b:用于标识进程的逻辑地址,不同进程的标识
c:有效端口:065535(两个字节),其中01023系统使用或保留端口。
3 传输协议: 通讯的规则常见协议:TCP,UDP
UDP
将数据源和目的封装成数据包中,不需要建立连接;
每个数据报的大小在限制在64k;
因无连接,是不可靠协议;
不需要建立连接,速度快
TCP
建立连接,形成传输数据的通道;
在连接中进行大数据量传输;
需要连接所以是可靠协议;
必须建立连接,效率会稍低
UDP
//1.创建客户端UDP的Socket
DatagramSocket ds = new DatagramSocket();
//2.封装数据 DatagramPacket数据报包 数据报包用来实现无连接包投递服务。
//2.1创建数据报包
//DatagramPacket( byte[] buf, int length, InetAddress address,int port)
//构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
byte[] bytes = "你好UPD,我来了".getBytes();
InetAddress address = InetAddress.getByName("192.168.47.1");
//参数3 服务器ip
//参数4:服务端socket的端口号
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, 9999);
//3.发送数据,发送数据报包
ds.send(dp);
//4.释放资源
ds.close();
//创建UDP服务端
//DatagramSocket( int port)
//创建数据报套接字并将其绑定到本地主机上的指定端口。
//创建服务端的Sokcet并暴露端口号
DatagramSocket ds = new DatagramSocket(9999);
//创建空的数据报包,来接收发送过来的报包
//DatagramPacket( byte[] buf, int length)
//构造 DatagramPacket,用来接收长度为 length 的数据包。
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//接收数据
System.out.println("服务器已经开启...等待接收数据");
//receive(dp) 方法的接收
//从此套接字接收数据报包。当此方法返回时,DatagramPacket 的缓冲区填充了接收的数据。
//数据报包也包含发送方的 IP 地址和发送方机器上的端口号。
//此方法在接收到数据报前一直阻塞。数据报包对象的 length 字段包含所接收信息的长度。
//如果信息比包的长度长,
ds.receive(dp); //阻塞的方法,如果数据没过来,就等待在这里。
//从数据报包中取数据
byte[] data = dp.getData();
//获取数据报包中数据的实际长度
int length = dp.getLength();
//再来获取发送方的IP
String ip = dp.getAddress().getHostAddress();
//把字节数据转换成字符串
String s = new String(data, 0, length);
System.out.println(ip+":给你发来消息,内容是:"+s);
//释放资源
ds.close();
AB互发消息
public class A {
public static void main(String[] args) {
//创建子线程开启服务器,来接收消息
new Thread(new Runnable() {
@Override
public void run() {
try {
//创建服务端的Socket,并暴露端口号
DatagramSocket ds = new DatagramSocket(9999);
System.out.println("A服务器已经开启,等待连接");
while (true) {
//接收发送过来的数据
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
ds.receive(dp);
//从数据报包中取出数据
byte[] data = dp.getData();
int length = dp.getLength();
//取发送者的IP
String ip = dp.getAddress().getHostAddress();
String s = new String(data, 0, length);
System.out.println(ip + ":B给你发来消息:" + s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
//在主线程给对方发消息
sendMsg();
}
private static void sendMsg() {
try {
//创建客户端的socket
DatagramSocket ds = new DatagramSocket();
//创建键盘录入对象
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.println("请输入消息");
String s = bfr.readLine();
if (s.equals("886")) {
break;
}
byte[] bytes = s.getBytes();
//创建数据报包
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.47.1"), 8888);
//发送数据
ds.send(dp);
}
//释放资源
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//
public class B {
public static void main(String[] args) {
//创建子线程开启服务器,来接收消息
new Thread(new Runnable() {
@Override
public void run() {
try {
//创建服务端的Socket,并暴露端口号
DatagramSocket ds = new DatagramSocket(8888);
System.out.println("B服务器已经开启,等待连接");
while (true) {
//接收发送过来的数据
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
ds.receive(dp);
//从数据报包中取出数据
byte[] data = dp.getData();
int length = dp.getLength();
//取发送者的IP
String ip = dp.getAddress().getHostAddress();
String s = new String(data, 0, length);
System.out.println(ip + ":A给你发来消息:" + s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
//在主线程给对方发消息
sendMsg();
}
private static void sendMsg() {
try {
//创建客户端的socket
DatagramSocket ds = new DatagramSocket();
//创建键盘录入对象
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.println("请输入消息");
String s = bfr.readLine();
if (s.equals("886")) {
break;
}
byte[] bytes = s.getBytes();
//创建数据报包
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.47.1"), 9999);
//发送数据
ds.send(dp);
}
//释放资源
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
TCP
//TCP客户端 Socket类
//TCP服务端 ServerSocket类
//创建客户端的sokcet
//Socket(InetAddress address, int port)
//创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
//Socket(String host, int port)
//创建一个流套接字并将其连接到指定主机上的指定端口号。
//参数:服务器ip和端口
Socket socket = new Socket("192.168.47.1", 9999);
//获取通道中的输出流
OutputStream out = socket.getOutputStream();
//发送数据
out.write("你好TCP".getBytes());
//释放资源
socket.close();
//1.创建服务端的Socket 并暴露端口号
ServerSocket ss = new ServerSocket(9999);
//2.侦听客户端的连接。
//Socket accept ()
//侦听并接受到此套接字的连接。
//阻塞式方法。accept()侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
System.out.println("服务器已经开启,等待连接。。。。");
Socket socket = ss.accept();
//.获取通道中的输入流
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
//转换成字符串
String s = new String(bytes, 0, len);
System.out.println(s);
//服务器关闭
ss.close();
//客户端键盘录入服务器控制台输出
public class TCPClient {
public static void main(String[] args) throws IOException {
//A:
//案例演示:
//客户端键盘录入服务器控制台输出
Socket sk = new Socket("192.168.47.1", 6666);
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
while (true){
System.out.println("请输入消息");
String msg= bfr.readLine();
//发送给服务端
OutputStream out= sk.getOutputStream();
out.write(msg.getBytes());
if ("886".equals(msg)) {
break;
}
}
//释放资源
bfr.close();
}
}
//
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(6666);
System.out.println("服务器已经开启,等待连接。。。");
Socket sk = ss.accept();
//循环读取客户端发来的消息
while (true){
InputStream in = sk.getInputStream();
String ip = sk.getInetAddress().getHostAddress();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String s = new String(bytes, 0, len);
if(s.equals("886")){
break;
}
System.out.println(ip+":给你发来消息内容是:"+s);
}
ss.close();
}
}
客户端键盘录入服务器写到文本文件
Socket sk = new Socket("192.168.47.1", 6666);
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
String line=null;
OutputStream out = sk.getOutputStream();
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(out));
while ((line=bfr.readLine())!=null){
System.out.println("请输入消息");
//可以把通道中的字节流,包装成字符流
bfw.write(line);
bfw.newLine();
bfw.flush();
if("886".equals(line)){
break;
}
}
sk.close();
//
//服务器接收客户端发来的消息,把消息保存到文本文件中
ServerSocket ss = new ServerSocket(6666);
System.out.println("服务端已经开启,等待连接。。。");
Socket sk = ss.accept();
//把通道中的输入流包装成字符流
InputStream in = sk.getInputStream();
BufferedReader bfr = new BufferedReader(new InputStreamReader(in));
String line = null;
BufferedWriter bfw = new BufferedWriter(new FileWriter("msg.txt"));
while ((line = bfr.readLine()) != null) {
if("886".equals(line)){
break;
}
//写入文本文件
bfw.write(line);
bfw.newLine();
bfw.flush();
System.out.println(line);
}
ss.close();
从文件读取内容,发送给服务端,服务端输出到控制台展示
Socket sk = new Socket("192.168.47.1", 6666);
//获取通道中的输入输出流
InputStream in = sk.getInputStream();
OutputStream out = sk.getOutputStream();
BufferedReader bfr = new BufferedReader(new FileReader("msg.txt"));
//可以把通道中的字节流,包装成字符流
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(out));
String line=null;
while ((line=bfr.readLine())!=null){
//读取一行写到通道中
bfw.write(line);
bfw.newLine();
bfw.flush();
}
//释放资源
sk.close();
bfr.close();
//
//服务端读取消息展示
ServerSocket ss= new ServerSocket(6666);
System.out.println("服务器已经开启,等待连接。。。。");
//侦听客户端
Socket sk = ss.accept();
//获取通道中的输入输出流
InputStream in = sk.getInputStream();
OutputStream out = sk.getOutputStream();
//把通道中的字节输入流,包装字符流
BufferedReader bfr = new BufferedReader(new InputStreamReader(in));
//读取消息展示
String line=null;
while ((line=bfr.readLine())!=null){
System.out.println(line);
}
ss.close();
客户端读取文本文件中的消息---->服务端读取法过来的消息,保存到文本文件中
Socket sk = new Socket("192.168.47.1", 6666);
//获取通道中的输入输出流
InputStream in = sk.getInputStream();
OutputStream out = sk.getOutputStream();
//客户端读取文件
BufferedReader bfr = new BufferedReader(new FileReader("demo.java"));
//包装通道中的字节输出流,为字符流
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(out));
String line=null;
while ((line=bfr.readLine())!=null){
bfw.write(line);
bfw.newLine();
bfw.flush();
}
//释放资源
sk.close();
bfr.close();
//
//服务端读取消息展示
ServerSocket ss = new ServerSocket(6666);
System.out.println("服务器已经开启,等待连接。。。。");
//侦听客户端
Socket sk = ss.accept();
//获取通道中的输入输出流
InputStream in = sk.getInputStream();
OutputStream out = sk.getOutputStream();
//把通道中的字节输入流,包装成字符
BufferedReader bfr = new BufferedReader(new InputStreamReader(in));
String line=null;
BufferedWriter bfw = new BufferedWriter(new FileWriter("demo_upload.java"));
while ((line=bfr.readLine())!=null){
bfw.write(line);
bfw.newLine();
bfw.flush();
}
ss.close();
bfw.close();
手动写标记告诉服务端
Socket sk = new Socket("192.168.47.1", 6666);
//获取通道中的输入输出流
InputStream in = sk.getInputStream();
OutputStream out = sk.getOutputStream();
//客户端读取文件
BufferedReader bfr = new BufferedReader(new FileReader("demo.java"));
//包装通道中的字节输出流,为字符流
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(out));
String line=null;
while ((line=bfr.readLine())!=null){
bfw.write(line);
bfw.newLine();
bfw.flush();
}
//客户上传完了,告诉服务端一声
//手动写一个标记给服务端
bfw.write("over");
bfw.newLine();
bfw.flush();
//读取服务端的反馈
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String s = new String(bytes, 0, len);
System.out.println(s);
//释放资源
sk.close();
bfr.close();
//
//服务端读取消息展示
ServerSocket ss = new ServerSocket(6666);
System.out.println("服务器已经开启,等待连接。。。。");
//侦听客户端
Socket sk = ss.accept();
//获取通道中的输入输出流
InputStream in = sk.getInputStream();
OutputStream out = sk.getOutputStream();
//把通道中的字节输入流,包装成字符
BufferedReader bfr = new BufferedReader(new InputStreamReader(in));
String line=null;
BufferedWriter bfw = new BufferedWriter(new FileWriter("demo_upload.java"));
while ((line=bfr.readLine())!=null){
//服务端读取到标记
if("over".equals(line)){
break;
}
bfw.write(line);
bfw.newLine();
bfw.flush();
}
//服务器给客户端,反馈一个上传成功
out.write("客户端你好!我服务端保存成功".getBytes());
ss.close();
bfw.close();
我们可以调用一个方法
void shutdownInput ()
此套接字的输入流置于“流的末尾”。
void shutdownOutput ()
禁用此套接字的输出流。
Socket sk = new Socket("192.168.47.1", 6666);
//获取通道中的输入输出流
InputStream in = sk.getInputStream();
OutputStream out = sk.getOutputStream();
//客户端读取文件
BufferedReader bfr = new BufferedReader(new FileReader("demo.java"));
//包装通道中的字节输出流,为字符流
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(out));
String line=null;
while ((line=bfr.readLine())!=null){
bfw.write(line);
bfw.newLine();
bfw.flush();
}
k.shutdownOutput();
//读取服务端的反馈
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String s = new String(bytes, 0, len);
System.out.println(s);
//释放资源
sk.close();
bfr.close();
//
//服务端读取消息展示
ServerSocket ss = new ServerSocket(6666);
System.out.println("服务器已经开启,等待连接。。。。");
//侦听客户端
Socket sk = ss.accept();
//获取通道中的输入输出流
InputStream in = sk.getInputStream();
OutputStream out = sk.getOutputStream();
//把通道中的字节输入流,包装成字符
BufferedReader bfr = new BufferedReader(new InputStreamReader(in));
String line=null;
BufferedWriter bfw = new BufferedWriter(new FileWriter("demo_upload.java"));
while ((line=bfr.readLine())!=null){
bfw.write(line);
bfw.newLine();
bfw.flush();
}
//服务器给客户端,反馈一个上传成功
out.write("客户端你好!我服务端保存成功".getBytes());
ss.close();
bfw.close();
一个服务端,连接多个客户端
//客户端给服务端上传文本文件。
//客户端读取文本文件中的消息---->服务端读取法过来的消息,保存到文本文件中
//客户端,从文件读取内容,发送给服务端,服务端输出到控制台展示
Socket sk = new Socket("127.0.0.1", 6666);
//获取通道中的输入输出流
InputStream in = sk.getInputStream();
OutputStream out = sk.getOutputStream();
//客户端读取文件
BufferedReader bfr = new BufferedReader(new FileReader("demo.java"));
//包装通道中的字节输出流,为字符流
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(out));
String line=null;
while ((line=bfr.readLine())!=null){
bfw.write(line);
bfw.newLine();
bfw.flush();
}
sk.shutdownOutput();
//读取服务端的反馈
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String s = new String(bytes, 0, len);
System.out.println(s);
//释放资源
sk.close();
bfr.close();
//
ServerSocket ss = new ServerSocket(6666);
System.out.println("服务器已经开启,等待连接。。。。");
//一个服务端,连接多个客户端
//写个死循环侦听多个客户端
int i=1;
while (true){
Socket sk = ss.accept();
System.out.println((i++)+"个客户已经连接。");
//多个客户端给服务端上传文件,我们在服务端给每个连接上来的客户端,开启一个单独的线程,来处理文件上传,
//也就是说多个客户端并发的上传,用户体验就好
//把建立的sk通道,传到线程中,去在线程中处理上传
new UploadThread(sk).start();
}
//
public class UploadThread extends Thread {
private Socket sk;
public UploadThread(Socket sk) {
this.sk=sk;
}
@Override
public void run() {
System.out.println("线程在执行");
try {
//获取通道中的输入输出流
InputStream in = sk.getInputStream();
OutputStream out = sk.getOutputStream();
//把通道中的字节输入流,包装成字符
BufferedReader bfr = new BufferedReader(new InputStreamReader(in));
String line = null;
//注意文件名,多个客户端上传文件,防止覆盖现象,注意取一个随机的文件名。
BufferedWriter bfw = new BufferedWriter(new FileWriter(System.currentTimeMillis()+"demo_upload.java"));
while ((line = bfr.readLine()) != null) {
bfw.write(line);
bfw.newLine();
bfw.flush();
}
//服务器给客户端,反馈一个上传成功
out.write("客户端你好!我服务端保存成功".getBytes());
//bfw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}