一、网络编程三要素
IP:网络中设备的标识,不易记忆,可用主机名
端口号:用于标识进程的逻辑地址,不同进程的标识
传输协议:通讯的规则常见协议:TCP,UDP
UDP
把数据打成一个数据包 , 不需要建立连接
数据包的大小有限制不能超过64k
因为无连接,所以属于不可靠协议(可能丢失数据)
因为无连接 ,所以效率高
TCP
需要建立连接,形成连接通道
数据可以使用连接通道直接进行传输,无大小限制
因为有链接,所以属于可靠协议
因为有链接,所以效率低
二、IP以及端口号
1、InetAddress类 —— 表示互联网协议 (IP) 地址
1)此类没有构造方法,创建对象使用方法实现
public static InetAddress getByName(String host) //参数为主机名或者IP的字符串表现形式
2)常用方法
public String getHostAddress() 获取IP
public String getHostName() 获取主机名
2、cmd IP查询
127.0.0.1 本地回环地址 用来做一些本地测试 不走交换机
ping IP地址 用来检测本机是否可以和指定的IP地址的计算机可以进行正常通讯
ipconfig /all 用来查看IP地址
getmac 用来获取mac地址
3、端口号 —— 逻辑端口
用来标示我们的计算机上的进程(正在运行的程序),端口号的有效范围应该是 0-65535,其中0-1024被系统占用或者保留
三、UDP协议
1、DatagramSocket类 —— 此类表示用来发送和接收数据报包的套接字
1)构造方法:
public DatagramSocket()
public DatagramSocket(int port) //参数port 端口号
public DatagramSocket(int port,InetAddress laddr) //参数laddr IP对象
2)常用方法:
public void close()关闭此数据报套接字
public void send(DatagramPacket p) 发送数据报包
public void receive(DatagramPacket p) 接收数据报包
public InetAddress getInetAddress() 返回此套接字连接的地址。如果套接字未连接,则返回 null。
2、DatagramPacket类 —— 此类表示数据报包
1)构造方法:
public DatagramPacket(byte[] buf,int length)
//参数 buf:保存传入数据报的缓冲区 length:一次要读取的长度
public DatagramPacket(byte[] buf,int length,InetAddress address,int port)
//参数 buf:包数据 length:包长度 address:目的IP port:目的端口号
2)解析数据:
public byte[] getData()返回用来接收或发送数据的缓冲区
public int getLength()返回将要发送或接收到的数据的长度
3、使用UDP传输数据
1)客户端:
public class SentDemo { public static void main(String[] args) throws IOException { InetAddress ip = InetAddress.getByName("接收端ip的字符串变现形式"); DatagramSocket ds = new DatagramSocket(); byte[] buf = "abc".getBytes(); DatagramPacket dp = new DatagramPacket(buf, buf.length, ip, 6666); //端口号不能定义成0-1024 ds.send(dp); ds.close(); } }
2)接收端:
public class ReceiveDemo { public static void main(String[] args) throws IOException { DatagramSocket ds = new DatagramSocket(6666); byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, buf.length); ds.receive(dp); System.out.println(new String(dp.getData(),0,dp.getLength())); ds.close(); } }
四、TCP协议 —— 使用管道输入输出流传输数据
1、服务器端
1)创建TCP通讯协议服务器端对象
ServerSocket ss = new ServerSocket("端口号");
2)监听客户端
Socket sk = ss.accept();
3)获取管道输入流对象
InputStream is = sk.getInputStream();
4)读取数据 //在使用管道输入流while循环接收数据的时候,不能以-1作为读取完毕的判定条件
//一般循环读取数据时,在客户端调用shutdownOutput()方法,服务端自动跳出循环
byte[] buf = new byte[1024 * 8];
int len = is.read(buf);
System.out.println(new String(buf,0,len));
5)释放资源
ss.close(); //一般服务器不用关闭
2、客户端
1)创建TCP通讯协议客户端对象
Socket sk = new Socket("服务端IP","服务端端口号");
2)获取管道流输出对象
OutputStream os = sk.getOutputStream();
3)写数据
os.write("需要传输的内容".getBytes());
4)释放资源
sk.close();
3、服务端反馈
服务端:
1)创建TCP通讯协议服务器端对象
2)监听客户端
3)获取管道输入流对象
4)读取数据
5)获取管道输出流对象
OutputStream os = sk.getOutputStream();
6)反馈信息
os.write("已收到".getBytes());
客户端:
1)创建TCP通讯协议客户端对象
2)获取管道流输出对象
3)写数据
4)获取管道输入流对象
InputStream is = sk.getInputStream();
4)接收反馈信息
byte[] buf = new byte[1024 * 8];
int len = is.read(buf);
System.out.println(new String(buf,0,len));
5)释放资源
4、shutdownOutput()方法
当客户端发送文件时,发送完毕后调用shutdownOutput()方法,服务端就会收到,停止接收;
sk.shutdownOutput();
5、TCP服务端多线程改进
public class TCPServerDemo { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(9527) ; //循环监听客户端 while(true){ Socket sk = ss.accept() ; // 开启线程 new Thread(new TCPServerThread(sk)).start() ; } } }
public class TCPServerThread implements Runnable { private Socket sk ; public TCPServerThread(Socket sk){ this.sk = sk ; } @Override public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream())) ; BufferedWriter bw = new BufferedWriter(new FileWriter("a.java")) ; // 一次读取一行 String line = null ; while((line = br.readLine()) != null){ bw.write(line) ; bw.newLine() ; bw.flush() ; } try { Thread.sleep(100) ; } catch (InterruptedException e) { e.printStackTrace(); } // 给客户端端反馈 // 获取输出流对象 OutputStream out = sk.getOutputStream() ; out.write("上传文件成功!".getBytes()) ; } catch (Exception e) { e.printStackTrace() ; } } }