一、网络编程基础
1、计算机网络
-
简介
-
计算机网络,是把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多计算机可以方便的相互传递信息,共享硬件、软件、数据等资源。计算机网络提供如下功能:
- 资源共享
- 信息传输和集中分布–
- 均衡负荷和分布处理
- 综合信息服务
-
实现计算机网络条件
- 硬件支持
- 软件支持
- ip、端口
- 协议
- http
- upd
- tcp/ip
-
2、网络范围
-
按照规模大小和延伸范围可以分为:局域网、城域网、广域网,其中 Internet 是最大的广域网。
-
按照网络的拓扑结构可以分为:星型网络、总线网络、环线网络、树形网络、星型环线网络等。
-
按照网络的传播介质可以分为:双绞线网、同轴电缆网、光纤网和卫星网等。
3、网络协议
-
OSI七层模型
- TCP、UDP都是属于传输层
- TCP、UDP都是依赖于ip
- HTTP属于应用层
- 依赖于tcp/ip协议实现
- TCP、UDP都是属于传输层
二、TCP/IP协议以及端口
1、IP概述
- IP 地址用于唯一地表示网络中的一个通信实体。基于 IP 协议网络中传输的数据包,都必须使用IP 地址来进行标识。
2、端口号
- 端口主要跟应用有关
3、InetAddress用法
(1)简介
- 通过此对象,获取ip地址及主机名、获取ip状态
(2)举例
package inetAddress用法;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class MainTest {
public static void main(String[] args) {
//InetAddress它就是描述IP地址
try {
//调用InetAddress类的静态方法getLocalHost()返回本地主机的地址。
InetAddress ipAddress = InetAddress.getLocalHost();
//获取本地ip
System.out.println("调用getHostAddress------------");
String hostAddress = ipAddress.getHostAddress();
System.out.println("hostAddress="+hostAddress);
System.out.println("调用getHostName------------");
String hostName = ipAddress.getHostName();
System.out.println("hostName="+hostName);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4、tcp/ip协议
(1)简介
-
TCP/IP 通信协议是一种可靠的网络协议。
-
可靠
- 通过TCP/IP协议实现数据传输,保证数据不丢失,对方肯定可以稳定接到数据
-
它是如何保证数据传输可靠性?
-
-
特点
-
它是面向连接的协议
- 三次握手
-
关闭连接
- 四次挥手
-
tcp/ip协议它是针对客户端、服务端而言
- server(服务端)
- client(客户端)
-
当连接成功之后,建立网络虚拟链路,此链路其实就是网络IO流,生成一个端点,此端点就是Socket(套接口字),通过Socket获取IO流的输入及输出
- socket.getInputStream():读数据
- socket.getOutputStream():写数据
-
(2)tcp/ip工作原理
-
工作步骤
- 客户端与服务端连接
- 三次握手
- 客户端与服务端连接
-
所谓三次握手(Three-Way Handshake)即建立TCP连接,是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发
-
建立连接关系之后,产生网络虚拟链路,就是网络IO流(Socket Stream)
-
如何实现数据通讯
-
客户端发送数据给服务端
- 获取针对客户端而言,获取输出流
OutputStream outPutStram = socket.getOutputStream()
再写数据:outPutStram.write(xxxx);
- 获取针对客户端而言,获取输出流
-
服务端发送数据给客户端
-
获取针对客户端而言的,获取输入流,读数据
InputStream inputstream=socket.getInputStream();
然后再读数据:inputstream.read(); -
关闭连接
- 四次挥手
5、第一个tcp/ip实例
需求
- 服务端发送字符串给客户端接受
(1)创建服务器端
package 第一个tcpip实例;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
* 编写一个tcpip的服务端程序
* */
public class TcpIpServer {
//定义端口
public static final int PORT=30001;
public static void main(String[] args) {
//创建ServerSocket对象
//创建tcpip服务端程序的类对象
ServerSocket ss=null;
try {
ss=new ServerSocket(PORT); //1、、获取端口
//调用一个方法accept()
//它是一个阻塞方法,等待客户端的连接,客户端一有连接,立即返回Socket对象
Socket socket=ss.accept(); //2、、等待客户端连接
//这里只是看看ip
//System.out.println("accept()方法 end socket ip="+socket.getInetAddress().getHostAddress());
//服务端发送字符串“hello world”给客户端接受
//3、、获取输出流对象
OutputStream outputStream = socket.getOutputStream();
//4、、写数据
byte buf[]="hello world".getBytes();//将helloworld转换成字节流存到数组中
outputStream.write(buf);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
(2)创建TCP客户端
package 第一个tcpip实例;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class TcpIpClient {
public static void main(String[] args) {
try {
//针对tcpip的服务端,进行连接
//1、、创建Socket对象,对服务端端口进行比配
Socket ss=new Socket("192.168.59.90", TcpIpServer.PORT);
//2、、创建输入流对象,客户端读取服务端发送过来的数据
InputStream inStream = ss.getInputStream();
byte []buf=new byte[32];
int readLen=inStream.read(buf);
String receiveMessage=new String(buf,0,readLen);
System.out.println("接受服务端发送过来的数据="+receiveMessage);
//关闭tcpip的连接
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
6、第二个tcp/ip协议
-
需求
-
客户端与服务端可以相互收发数据
-
实例
- 服务端的程序
package 第二个tcpip实例;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public final static int PORT=30004;//1、、获取端口
public static void main(String[] args) {
//创建ServerSocket
ServerSocket ss=null;
try {
ss=new ServerSocket(PORT);
//等待客户端的连接,此accept方法是等待、阻塞方法
Socket socket=ss.accept();//2、、等待连接
//3、、发送数据给客户端
OutputStream outputStream=socket.getOutputStream();
outputStream.write("欢迎光临!".getBytes());
outputStream.flush();
//4、、接受客户端发送过来的数据
InputStream inStream=socket.getInputStream();
byte buf[]=new byte[32];
int readLen=inStream.read(buf);
System.out.println("接受客户端发送过来的数据="+new String(buf,0,readLen));
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 客户端的程序
package 第二个tcpip实例;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) {
Socket socket=null;
try {
socket=new Socket("192.168.59.90",Server.PORT);//1、、服务端ip及服务端端口
InputStream inputStream=socket.getInputStream();
//定义buf数组
byte buf[]=new byte[32];
int readLen=inputStream.read(buf);
//获取数据
String recMessage=new String(buf,0,readLen);
System.out.println("recMessage="+recMessage);
//客户端又发送数据给服务端
OutputStream outputStream=socket.getOutputStream();
outputStream.write("我已经收到".getBytes());
outputStream.flush();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(socket!=null)
{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
7、第三个tcp/ip实例
-
需求
-
实现点对点的tcpip聊天功能
-
所需技术
- 网络编程
- IO流
- 多线程
-
代码实现
-
编写服务端程序
package 第三个tcpip实例;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TcpIpChatServer {
public static final int PORT=30005;
//获取键盘内容
private static Scanner sc=new Scanner(System.in);
public static void main(String[] args) throws IOException {
//创建tcpip的Server端的对象
ServerSocket ss=new ServerSocket(PORT);
//等待监听客户端的连接
Socket socket=ss.accept();
System.out.println("有客户端连接,客户端ip="+socket.getInetAddress().getHostAddress());
//获取输出流的对象
OutputStream outputStream=socket.getOutputStream();
//创建一个打印流
PrintStream ps=new PrintStream(outputStream);
/*
* 可以通过主线程实现写功能
* */
System.out.println("退出输入按q,请输入发送给客户端的内容:");
//定义发送消息的变量
String sendMessage=null;
while((sendMessage=sc.nextLine())!=null)
{
if(sendMessage.equals("q"))
{
//退出聊天
break;
}
ps.println(sendMessage);
ps.flush();
}
}
/*
* 实现读线程
* */
}
- 编写客户端程序
package 第三个tcpip实例;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class TcpIpChatClient {
public static void main(String[] args) throws UnknownHostException, IOException {
//创建Socket对象
Socket socket=new Socket("192.168.59.90", TcpIpChatServer.PORT);
//创建一个专门处理读数据的线程
new TcpIpChatClient().new ReadDataThread(socket).start();
}
//定义一个读数据的线程类
public class ReadDataThread extends Thread
{
private Socket socket;
private BufferedReader br;
public ReadDataThread(Socket socket) throws IOException
{
this.socket=socket;
//将输入流装饰成缓存流来读取数据
//将inputstream---->inputStreamReader(转换流)---->bufferReader
br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
/*
* 可以在子线程的执行体读取数据
* */
@Override
public void run() {
String receveMessage=null;
//读数据
try {
while((receveMessage=br.readLine())!=null)
{
System.out.println("接受服务端发送过来的数据="+receveMessage);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三、UDP协议应用
1、简介
-
UDP协议:用户数据报协议
- udp协议它是基于数据报,以数据报为单位来传输
-
传输不可靠的数据协议
- 不可靠的数据:传输过程中可能存在丢失
-
非面向连接协议
-
它没有很明确的客户端、服务端之分
2、UDP协议的优缺点
-
缺点
- 数据不可靠
-
优点
- 传输数据非常高效
-
作用域
-
高效、实时的效果
-
视频传输
-
游戏
-
-
3、UDP协议传输原理
-
udp协议它是以数据报为单位传输,它只管发送,不管你是否接收成功,它是没有应答机制(ack机制)
数据报包括 -
数据部分
-
报头
- 目标IP
- 端口
4、UDP核心类
(1)DatagramSocket 类
-
发送、接受的数据报
-
DatagramSocket的构造器
- DatagramSocket(port):绑定端口,创建接收方
- DatagramSocket():不需要绑定端口,它是发送方
- receive(DatagramPacket p) :接受数据报
- send(DatagramPacket p) :发送数据报
(2)DatagramPacket 类
-
此类描述数据报内容
- 数据部分
- ip部分
- 端口
-
分析DatagramPacket的构造器
-
DatagramPacket(byte[] buf, int length) :它肯定是属于接受数据报的对象,构造 DatagramPacket,用来
接收
长度为 length 的数据包。 -
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
- 将长度为length的字节数组发送到目标主机的ip及端口
-
DatagramPacket(byte[] buf, int offset, int length) :起始位置是offset、长度为length的字节数组接收数据报内容
-
5、第一个udp实例
-
需求
- 主机A发送字符串数据给主机B接受,通过UDP协议实现
-
代码
- A程序代码
package udp协议应用;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class A {
public static void main(String[] args) throws IOException {
//创建DatagramSocket对象,作为发送方,它就不需要绑定端口
DatagramSocket ds=new DatagramSocket();
String sendMessage="helloworld";
//定义数据报
DatagramPacket dp=new DatagramPacket(
sendMessage.getBytes(),
sendMessage.getBytes().length,
InetAddress.getByName("192.168.59.21"),
B.PORT);
//发送数据报
ds.send(dp);
}
}
B程序代码
package udp协议应用;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class B {
public static final int PORT=30001;
public static void main(String[] args) throws IOException {
//创建DatagramSocket,绑定port,它是属于接受方
DatagramSocket ds=new DatagramSocket(PORT);
//调用receive方法接受数据,它是一个阻塞方法
//定义字节数组
byte []buf=new byte[32];
//创建DatagramPacket对象,它是属于接受数据报,它是将数据报的内容存储到buf数组
DatagramPacket dp=new DatagramPacket(buf, buf.length);
//将接受到数据存储到参数的数据报里面
ds.receive(dp);
//将数据报的字节数组转换成String字符串类型
String recMessage=new String(dp.getData(),0,dp.getLength());
System.out.println("接受A主机发送过来的数据="+recMessage);
}
}
6、第二个udp实例
-
需求
- 基于udp协议的实现点对点的聊天功能
-
所需技术
- udp协议
- 多线程实现
-
举例
- A应用代码
package 点对点聊天;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
public class A {
private static Scanner sc=new Scanner(System.in);
public static final int PORT=30001;
public static void main(String[] args) throws IOException {
//定义发送方的DatagramSocket对象
DatagramSocket sendDs=new DatagramSocket();
//定义接受方的DatagramSocket对象,绑定端口
DatagramSocket receiveDs=new DatagramSocket(PORT);
//启动子线程接受数据
new A().new ReadDataThread(receiveDs).start();
/*
* 主线程负责发送数据
* */
System.out.println("请输入发送到B主机的内容:");
String sendContent=null;
while((sendContent=sc.nextLine())!=null)
{
System.out.println("请输入发送到B主机的内容:");
//DatagramPackage对象(发送包),绑定ip及端口
DatagramPacket sendPackage=new DatagramPacket(
sendContent.getBytes(),
sendContent.getBytes().length,
InetAddress.getByName("192.168.59.21"),
B.PORT
);
//发送包
sendDs.send(sendPackage);
}
}
/*
* 子线程负责读取数据
* */
public class ReadDataThread extends Thread
{
private DatagramSocket receiveDs;
public ReadDataThread(DatagramSocket receiveDs)
{
this.receiveDs=receiveDs;
}
@Override
public void run() {
while(true)
{
byte []buf=new byte[128];
//创建数据报(属于接受数据的数据报)
DatagramPacket dp=new DatagramPacket(buf, buf.length);
try {
receiveDs.receive(dp);
//将字节数组转换成字符串
String recContent=new String(dp.getData(),0,dp.getLength());
System.out.println("接受B主机发送过来的数据="+recContent);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
B应用的代码
package 点对点聊天;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
import 点对点聊天.A.ReadDataThread;
public class B {
private static Scanner sc=new Scanner(System.in);
public static final int PORT=30002;
public static void main(String[] args) throws IOException {
//定义发送方的DatagramSocket对象
DatagramSocket sendDs=new DatagramSocket();
//定义接受方的DatagramSocket对象,绑定端口
DatagramSocket receiveDs=new DatagramSocket(PORT);
//启动子线程接受数据
new B().new ReadDataThread(receiveDs).start();
/*
* 主线程负责发送数据
* */
System.out.println("请输入发送到A主机的内容:");
String sendContent=null;
while((sendContent=sc.nextLine())!=null)
{
System.out.println("请输入发送到A主机的内容:");
//DatagramPackage对象(发送包),绑定ip及端口
DatagramPacket sendPackage=new DatagramPacket(
sendContent.getBytes(),
sendContent.getBytes().length,
InetAddress.getByName("192.168.59.21"),
A.PORT
);
//发送包
sendDs.send(sendPackage);
}
}
/*
* 子线程负责读取数据
* */
public class ReadDataThread extends Thread
{
private DatagramSocket receiveDs;
public ReadDataThread(DatagramSocket receiveDs)
{
this.receiveDs=receiveDs;
}
@Override
public void run() {
while(true)
{
byte []buf=new byte[128];
//创建数据报(属于接受数据的数据报)
DatagramPacket dp=new DatagramPacket(buf, buf.length);
try {
receiveDs.receive(dp);
//将字节数组转换成字符串
String recContent=new String(dp.getData(),0,dp.getLength());
System.out.println("接受A主机发送过来的数据="+recContent);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}