TCP/UDP

  1. UDP:用于发送数据包(音频、视频…),开销比TCP少;数据无需按照顺序发送到接收方,在过程中有丢包的可能,即接收者需要对数据包进行排序请求重新发送丢失的数据包

Socket

Socket socket = new Socket("time-A.timefreq.bldrdoc.gov", 13);
简介:Socket构造器通过地址和端口号,启动该程序内部与外部的连接;如果连接失败或其他问题将报异常

获取数据输入流:一直持续到流发送完毕且服务器断开

  • InputStream inputStream = socket.getInputStream();

一、读写数据时,当前线程也会被阻塞直到操作成功或产生超时为止->>设置超时

  • socket.setSoTimeout(10000);

二、Socket构造器,在建立连接之前会一直阻塞,直到与主机建立连接->>connect方法

  • Socket socket = new Socket();<br />``socket.connect(new InetSocketAddress("time-A.timefreq.bldrdoc.gov",13), 10000);

可中断套接字

简介:当前套接字线程在建立连接前连接后,读取数据线程将一直阻塞;>>>可以取消那些看似不会产生结果的连接。但是,当线程因套接字无法响应而发生阻塞时,则无法通过调用interrupt来解除阻塞

**static SocketChannel open(SocketAddress address)**

  1. 它所拥有的readwrite方法都是通过使用Buffer对象(缓冲)来实现的
  2. 如果不想处理缓冲区,可以使用Scanner类从SocketChannel中读取信息,
    • 因为Scanner有一个带**ReadableByteChannel**参数的构造器
  3. 通过调用静态方法**Channels.newOutputStream**,可以将通道转换成输出流

**InetSocketAddress(String hostname,int port)**

  • 通过主机和端口参数创建一个地址对象,并在创建过程中解析主机名。如果主机名不能被解析,那么该地址对象的unresolved属性将被设为true

**boolean isUnresolved()**

  • 如果不能解析该地址对象,则返回true

InetAddress

主机名与IP地址转换->>返回所有代表主机的对象

  • InetAddress address = InetAddress._getByName_("time-A.timefreq.bldrdoc.gov")
  • getByAllName()

获取本机地址/主机名:getLocalHost()、getHostName()

  • InetAddress localHost = InetAddress._getLocalHost_();

二进制、十进制数方式表示地址信息:byte[] getAddress()、String getHostAddress()

  • byte[] address = address.getAddress();
  • String hostAddress = address.getHostAddress();

ServerScoket

ServerSocket serverSocket = new ServerSocket(8189);<br />Socket accept = serverSocket.accept();

简介:创建服务器套接字,指定端口号并accept()一直等待连接
关闭服务器:accept.close()

  1. public class server {
  2. public static void main(String[] args) {
  3. try {
  4. //创建服务端
  5. ServerSocket serverSocket = new ServerSocket(8189);
  6. Socket accept = serverSocket.accept();
  7. //获取数据输入流,提供数据输出流
  8. InputStream inputStream = accept.getInputStream();
  9. OutputStream outputStream = accept.getOutputStream();
  10. Scanner scanner = new Scanner(inputStream);
  11. PrintStream printStream = new PrintStream(outputStream,true);
  12. printStream.println("hello! Enter BYE to exit.");
  13. boolean exit = false;
  14. while (!exit){
  15. String s = scanner.nextLine();
  16. printStream.println("Jack:"+s);
  17. if (s.trim().equals("BYE"))
  18. exit = true;
  19. accept.close();
  20. }
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }

处理多个客户端

简介:简单服务器会拒绝多客户端连接,使得某个用户可能会因长时间地连接服务而独占服务,其实我们可以运用线程的魔力把这个问题解决得更好

  1. package mynet;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.PrintWriter;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. import java.nio.charset.Charset;
  9. import java.util.Scanner;
  10. /**
  11. * @author Charles
  12. * @description
  13. * @create 2021-12- 上午11:45
  14. */
  15. public class server {
  16. public static void main(String[] args) {
  17. try {
  18. int i = 1;
  19. ServerSocket serverSocket = new ServerSocket(8189);
  20. while(true){
  21. Socket accept = serverSocket.accept();
  22. System.out.println("Client="+i);
  23. ThreadServer server = new ThreadServer(accept);
  24. Thread thread = new Thread(server);
  25. thread.start();
  26. i++;
  27. }
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }
  33. class ThreadServer implements Runnable {
  34. private Socket accept;
  35. public ThreadServer(Socket socket) {
  36. this.accept = socket;
  37. }
  38. @Override
  39. public void run() {
  40. try {
  41. InputStream in = accept.getInputStream();
  42. OutputStream out = accept.getOutputStream();
  43. Scanner scanner = new Scanner(in);
  44. PrintWriter printWriter = new PrintWriter(out,true, Charset.forName("gbk"));
  45. System.out.println("Hello ,Neo! (exit)");
  46. boolean flag = false;
  47. while(!flag && scanner.hasNext()){
  48. String str = scanner.nextLine();
  49. printWriter.println("<<服务器>>"+str);
  50. if(str.trim().equals("exit")){
  51. flag = true;
  52. }
  53. }
  54. } catch (IOException e) {
  55. e.printStackTrace();
  56. }finally {
  57. try {
  58. accept.close();
  59. } catch (IOException e) {
  60. e.printStackTrace();
  61. }
  62. }
  63. }
  64. }

半关闭

简介:半关闭(half-close)提供了这样一种能力:套接字连接的一端可以终止其输出,同时仍旧可以接收来自另一端的数据。
通过关闭一个套接字的输出流来表示发送给服务器的请求数据已经结束,但是必须保持输入流处于打开状态
socket.shutdownInput();<br />socket.shutdownOutput();


URL、URI

InputStream inputStream = url.openStream();

  • 获得该资源的内容

简介:
URL:统一资源定位符、URI:统一资源标识符;
URI是个纯粹的语法结构,包含用来指定Web资源的字符串的各种组成部分。URL是URI的一个特例,它包含了用于定位Web资源的足够信息
在Java类库中,URI类不包含任何用于访问资源的方法,惟一作用>>解析<<
URL类可以打开一个到达资源的流。URL类只能作用于Java类库知道该如何处理的模式,例如http:https:、ftp:、本地文件系统(file:)和JAR文件(jar:)。

RFC 2396(标准化URI的文献)还支持一种基于注册表的机制
image.png
image.png

使用URLConnection获取信息

简介:URLConnection类具有很多表面之外的神奇功能,尤其在处理请求和响应消息头时;严格遵循建立连接的每个步骤显得非常重要

一、调用URL类中的openConnection方法获得URLConnection对象
URLConnection urlConnection = url.openConnection();

二、使用以下方法来设置任意的请求属性
image.png

三、调用connect方法连接远程资源
connection.connect();

四、与服务器建立连接后,可以查询头信息。

  1. getHeaderFieldKey(int n)getHeaderField(int n)枚举了消息头的所有字段
    • 获得响应头的第n个键,其中n从1开始!
    • 如果n为0或大于消息头的字段总数,该方法将返回null值。
  2. getHeaderFields()返回一个封装了响应头字段的Map对象

image.png

五、访问资源数据。
由标准内容类型(比如text/plain和image/gif)的对象返回,需要使用com.sun层次结构中的类来进行处理。也可以注册自己的内容处理器

  • **getInputStream**方法获取一个输入流用以读取信息(这个输入流与URL类中的openStream方法所返回的流相同)。

setDoInput、setDoOutput。

简介:在默认情况下,建立的连接只产生从服务器读取信息的输入流,并不产生任何执行写操作的输出流。
一、获得输出流(用于向一个Web服务器提交数据)
connection.setDoOutput(true);

二、设置某些请求头(request header)。请求头是与请求命令一起被发送到服务器的

setIfModifiedSince(long time)

  • 获取那些自从某个给定时间以来被修改过的数据。time参数指从1970年1月1日午夜开始计算的秒数

setUseCaches()

  • 用于命令浏览器首先检查它的缓存;

setAllowUserInteraction()

  • 用于在访问有密码保护的资源时弹出对话框,以便查询用户名和口令

setUseCaches()、setAllowUserInteraction()>>>>>只作用于Applet

setRequestProperty() 用来设置对特定协议起作用的任何“名-值(name/value)对”

URLConnection方法

void setConnectTimeout(int timeout)
int getConnectTimeout()

  • 设置或得到连接超时时限(单位:毫秒)。超时后 那么相关联的输入流的connect方法就会抛出一个SocketTimeoutException异常

java.net.URLEncoder
static String encode(String s,String encoding)>>采用指定的字符编码模式(推荐使用“UTF-8”)

  • 对字符串s进行编码,并返回它的URL编码形式。

提交表单数据

简介:
一、 GET方法,只需将参数附在URL的结尾处即可;以?开头,参数之间用&字符分隔开;大多数浏览器都对GET请求中可以包含的字符数作了限制

二、POST方法,并不需要在URL中添加任何参数,而是从URLConnection中提供输出流,并将”名-值”对写入该流中;仍然需要对这些值进行URL编码,并用&字符将它们隔开

参数的值将遵循下面的规则使用URL编码模式进行编码:

  1. 保留字符A-Z、a-z、0-9以及.-*_。1
  2. 用+字符替换所有的空格。
  3. 将其他所有字符编码为UTF-8,
  4. 并将每个字节都编码为%后面紧跟一个两位的十六进制数字。

步骤:>>>>>
首先打开连接、调用setDoOutput(true)以及打开输出流
然后,

  1. 查看HTML标签,找到相应的from表单
  2. 查看action属性,onSubmit属性
  3. 根据要处理的字段名,在代码中进行赋值

其次,对要发送的内容进行整理:对每一个键-值对进行“=”、“&”、“编码”
最后,我们从服务器读取响应信息

总结:>>>

  • 如果脚本运行出现错误,那么调用connection.getInputStream()时就会抛出一个FileNotFoundException异常
  • 为了捕捉这个错误页面,可以将URLConnection对象转型为HttpURLConnection类并调用它的getErrorStream方法

小结:>>>
image.png

  1. public class SocketTest {
  2. public static void main(String[] args) throws IOException {
  3. //页面URL+表单页面
  4. URL url = new URL("https://www.igdcc.com/e/member/login/../doaction.php");
  5. //建立连接
  6. URLConnection connection = url.openConnection();
  7. //获取输出流
  8. connection.setDoOutput(true);
  9. //处理流
  10. OutputStream outputStream = connection.getOutputStream();
  11. PrintStream out = new PrintStream(outputStream);
  12. //表单信息
  13. String name = URLEncoder.encode("2698471124");
  14. String password = URLEncoder.encode("2698471124");
  15. //整理数据
  16. out.println("username="+name+"&password="+password);
  17. out.close();
  18. try {
  19. InputStream inputStream = connection.getInputStream();
  20. Scanner scanner = new Scanner(inputStream);
  21. while (scanner.hasNextLine()){
  22. System.out.println(scanner.nextLine());
  23. }
  24. }catch (Exception e){
  25. //访问页面错误处理
  26. InputStream errorStream = ((HttpURLConnection) connection).getErrorStream();
  27. Scanner scanner = new Scanner(errorStream);
  28. while (scanner.hasNextLine()){
  29. System.out.println(scanner.nextLine());
  30. }
  31. }
  32. }
  33. }