1、什么是网络编程?
网络编程就是2个或多个设备之间进行数据交换。数据之间的传递本身没有多大的难度,无非就是将一个设备中的数据发送给另外一个设备,然后接收另外一个设备反馈过来的数据。
在网络编程中,都是基于请求/响应方式的,
发起连接程序,也就是第一次请求的程序,被称作为客户端(client)
等待其它程序连接的程序被称之为服务器(server).
注:客户端程序在需要的时候启动,而服务端程序为了能够时刻响应连接,则需要一直启动。
例如打电话,首先拨号的人类似于客户端,而接听电话的人必须保持电话畅通类似于服务器。连接一旦建立成功,服务端和客户端就可以进行数据传递了。
2、网络模型
网络模型分为:OSI参考模型和TCP/IP参考模型,如下图:
3、网络通讯3要素:传输协议、ip地址、端口号
1)、传输协议:就是通讯的规则,常见的协议如:TCP、UDP
2)、IP地址:InetAddress,就是网络中设备的标识,如本地地址:127.0.0.1,主机名:localhost
3)、端口号:用于标识进程的逻辑地址,不同进程的标识,有效端口为0-65535,其中0-1024是系统使用或保留的端口
4、TCP和UDP的区别:
1)、传输数据限制:TCP对传输的数据没有大小限制
UDP的每个数据包的大小限制在64k以内
2)、是否连接:Tcp需要建立连接,形成传输的数据通道
UDP将数据源和目的地封装到数据包中,不需要建立连接
3)、传输是否可靠:TCP通过三次握手完成连接,是可靠协议
UDP因无需建立连接,是不可靠协议
4)、速度:TCP必须建立连接,效率会稍低
UDP无需建立连接,速度快
应用场景:tcp如:电话通话,必须连接,对方同意才可以发送数据(不然就等待),不能丢失数据。
udp如:聊天、对讲机就是udp的,它是面向无连接(不管在不在,知不知道,只管发送,求速度),丢数据也不管。速度
快,数据被分成包
5、InetAddress与Socket常用类和方法
InetAddress:构造方法私有,不能直接创建对象
InetAddress getByName(String host):在给定主机名的情况下,确定主机的ip地址
InetAddress getLocalHost():返回本地主机
inetAddress.getHostAddress():得到主机地址
inetAddress.getHostName():得到主机名称
6、什么是socket?
socket就是为网络服务提供的一种机制
通信的两端都有socket
网络通信其实就是socket间的通信
数据在两个socket之间通过IO传输
7、TCP传输
在BIO中,2个端点建立连接后会有一个传输数据的通道,这个通道就是流,而且是建立在网络基础上的流,称之为socket流。
该流中既有读取,也有写入。
2)、tcp的2个端点,一个是客户端,对应的对象是Socket
一个是服务端,对应的对象是ServerSocket
3)、tcp客户端创建步骤,如下:
步骤1、建立tcp的socket服务,最好明确具体的地址和端口。
这个对象创建时,就已经对指定ip和端口进行连接(三次握手)
步骤2、如果连接成功,就意味着通道建立了,socket流就已经产生了。
只要获取到socket流中的读取流和写入流即可,只要通过getInputStream和getOutputStream就可以获取这2个流对象
步骤3、关闭资源
代码如下:
package com.cn.io;
import java.io.*;
import java.net.Socket;
/**
* 客户端向服务器端发送一个数
* */
public class SocketClient {
public static void main(String[] args) throws Exception{
Socket socket=new Socket("localhost",8532);
OutputStream os=socket.getOutputStream(); //获取了socket流中的输出流对象
os.write("hello,我是来自客户端的请求dsdsdsds".getBytes());
socket.close();
}
}
Tcp服务端创建步骤如下
第一步、创建服务端socket对象ServerSocket,并监听一个端口
第二步、服务端为了给客户端提供服务,获取客户端的内容,可以通过accept方法获取连接过来的客户端对象
第三步、可以通过获取到的socket对象中的socket流和具体的客户端进行通讯
第四步、如果通讯结束,关闭资源。注意:要先关闭客户端,再关闭服务端
代码如下:
package com.cn.io;
import sun.applet.Main;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
public static void main(String[] args) throws IOException {
//1.获取服务器端socket,并监听端口
ServerSocket serverSocket=new ServerSocket(8532);
//2.获取客户端对象
Socket socket=serverSocket.accept();
//3.获取socket对象中的socket流和具体的客户端进行通讯
InputStream is=socket.getInputStream();
//4.读取客户端的数据,使用客户端对象的socket读取流
byte[] b=new byte[1024]; //定义一个byte类型的数组,数组长度为1024
int len=is.read(b); //通过输入流读取数组中的数据
String text=new String(b,0,len); //byte数组b从下标为0开始前进len个下标的那一段数组变为字符串text
System.out.println(text);
//如果通讯结束,关闭资源,注意要先关闭客户端,再关闭服务端
socket.close();
serverSocket.close();
}
}
总结:对于UDP和TCP,既可以定义输出流也可以创建输入流,具体的情况根据需要构建。
比如:我们需要客户端给服务端发送数据,服务端在给客户端响应数据,那么就要在客户端和服务器端分别多加一个输入流和输出流,否则,发布出去、收不到。
代码如下:
客户端:
package com.cn.io;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
//1.获得客户端socket
Socket socket=new Socket("localhost",8901);
//2.获得输出流
OutputStream os=socket.getOutputStream();
//3.输出消息到服务端
os.write("你好,我是服务端消息".getBytes());
//关闭socket
socket.shutdownOutput();
//4.得到输入的消息
InputStream is=socket.getInputStream();
byte[] b=new byte[1024];
int len=is.read(b);
System.out.println(new String(b,0,len));
//关闭
socket.close();
}
}
服务器端:
package com.cn.io;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception{
//1.获得服务器端socket,并监听端口
ServerSocket serverSocket=new ServerSocket(8901);
//2.获取客户端对象
Socket socket=serverSocket.accept();
//3.获得客户端输入流
InputStream is=socket.getInputStream();
//4.声明一个byte类型的数组,数组长度为1024
byte[] b=new byte[1024];
int len;
while((len=is.read(b))!=-1){
System.out.println(new String(b,0,len));
}
//5.因为是双向通信的,可以在此处定义一个输出流,输出数据到服务器端
OutputStream os=socket.getOutputStream();
os.write("你好,我是来自服务端的消息".getBytes());
//6.关闭,先关闭客户端,再关闭服务端
socket.close();
serverSocket.close();
}
}