沈阳网站建设公司电话哪些网站做任务可以赚钱的
2026/6/9 22:50:42 网站建设 项目流程
沈阳网站建设公司电话,哪些网站做任务可以赚钱的,开封公司做网站,seoul是什么意思文章目录Ⅰ. UDP 和 TCP 的区别Ⅱ. UDP 套接字编程一、常用方法二、服务端三、客户端Ⅲ. TCP 套接字编程一、常用方法二、服务端① 多线程版本② 线程池版本三、客户端Ⅰ. UDP 和 TCP 的区别 特性TCP#xff08;传输控制协议#xff09;UDP#xff08;用户数据报协议#…文章目录Ⅰ. UDP 和 TCP 的区别Ⅱ. UDP 套接字编程一、常用方法二、服务端三、客户端Ⅲ. TCP 套接字编程一、常用方法二、服务端① 多线程版本② 线程池版本三、客户端Ⅰ. UDP 和 TCP 的区别特性TCP传输控制协议UDP用户数据报协议类型面向连接、面向字节流无连接、面向数据报可靠性可靠数据按顺序到达、无丢包不可靠可能丢包、乱序缓冲区既有接收缓冲区也有发送缓冲区只有接收缓冲区速度较慢需握手、确认等较快没有连接管理应用场景文件传输、Web、聊天视频直播、游戏、广播Java支持类Socket、ServerSocketDatagramSocket、DatagramPacketⅡ. UDP 套接字编程一、常用方法UDP是无连接的因此每次发送数据报前都需要指定目标地址和目标端口而TCP则只需要创建套接字时候绑定即可在Java中创建一个DatagramSocket对象就是在操作系统中打开了一个socket文件通过这个文件可以读写数据而该文件负责将内容与网卡进行交互从而达到网络通信功能。DatagramPacket就是一个数据报DatagramSocket是真正的套接字文件使用时候就是通过DatagramSocket中的send/receive方法来传输一个个数据报DatagramPacket。类名返回值功能DatagramSocket()构造方法创建一个 UDP 套接字系统会随机分配一个可用端口DatagramSocket(int port)构造方法绑定到指定端口DatagramSocket(int port, InetAddress laddr)构造方法绑定到指定 IP 和端口DatagramSocket(SocketAddress bindaddr)构造方法使用 InetSocketAddress 绑定地址和端口send(DatagramPacket p)void发送一个数据报包到目标地址receive(DatagramPacket p)void阻塞接收一个数据报包close()void关闭套接字释放资源isClosed()boolean判断套接字是否已关闭setSoTimeout(int timeout)void设置接收数据的超时时间毫秒getSoTimeout()int获取当前接收超时时间setReuseAddress(boolean on)void设置是否允许地址重用getLocalPort()int获取本地绑定的端口号getLocalAddress()InetAddress获取本地绑定的 IP 地址DatagramPacket(byte[] buf, int length)构造方法创建空数据报用于接收数据DatagramPacket(byte[] buf, int length, InetAddress addr, int port)构造方法创建用于发送的数据报指定目标地址和端口DatagramPacket(byte[] buf, int offset, int length, InetAddress addr, int port)构造方法发送指定字节数据支持偏移和长度控制DatagramPacket(byte buf[], int offset, int length, SocketAddress address)构造方法创建数据报通过SocketAddress直接指定端口和地址getData()byte[]获取数据报的缓冲区内容setData(byte[] buf)void设置数据缓冲区getLength()int获取数据报中有效数据长度setLength(int length)void设置数据报的有效数据长度getSocketAddress()SocketAddress获取地址、端口的一个结构体 相当于下面两个方法的结合getAddress()InetAddress获取目标地址或发送者地址getPort()int获取目标端口或发送者端口setAddress(InetAddress addr)void设置数据包的目标地址setPort(int port)void设置数据包的目标端口注意事项要构造InetAddress的话需要调用InetAddress.getByName(s)静态方法其中s是地址字符串比如127.0.0.1最后就能拿到的就是地址为s的InetAddress对象一般构造DatagramPacket用getSocketAddress()的版本比较方便因为这个方法实际上就包括了端口和地址如下图所示创建DatagramPacket的时候要传入的byte数组实际上是一个应用层的缓冲区通常建议缓冲区大小设置为大于或等于预期最大UDP包大小比如4096或8192。此外要使用req.getLength()来获取实际接收数据的长度而不是buf.length即在读取数据时要用new String(req.getData(), 0, req.getLength())避免读到多余的空字节。二、服务端接收客户端发来的请求并且进行解析处理请求封装成数据报进行响应/** * 服务器不需要知道数据从哪里来所以不需要用字段来存放客户端的IP和端口直接从请求中获取即可 */publicclassServer{privateDatagramSocketsocketnull;// 通信就靠DatagramSocket对象publicServer(intport)throwsSocketException{socketnewDatagramSocket(port);// 服务端需要指定port让别人来连接}publicvoidstart()throwsIOException{System.out.println(服务器启动);while(true){// 1. 阻塞接收客户端发来的请求并且进行解析DatagramPacketreqnewDatagramPacket(newbyte[4096],4096);socket.receive(req);StringdatanewString(req.getData(),0,req.getLength());// 从 DatagramPacket 取到有效的数据// 2. 处理请求Stringoutcomefunc(data);// 3. 封装成数据报进行响应注意要填写目的端口和ipDatagramPacketrespnewDatagramPacket(outcome.getBytes(),0,outcome.getBytes().length,//req.getAddress(), req.getPort()); // 可以这样子写但是麻烦推荐下面的写法req.getSocketAddress());socket.send(resp);// 打印日志看看效果System.out.printf([%s:%d] req: %s, resp: %s\n,req.getAddress(),req.getPort(),data,outcome);}}// 业务代码不是现在的重点publicStringfunc(Stringdata){returndata;}publicstaticvoidmain(String[]args)throwsIOException{ServerservernewServer(8080);server.start();}}三、客户端构造请求数据报注意要传入目的端口和IP到数据报中发送请求到服务器接收服务器发来的响应然后进行解析/** * 1. 因为客户端在发送数据报的时候需要知道服务器的IP和端口并且由于UDP * 每次发送数据都得传入服务器的IP和端口所以需要用单独的字段来保存 * * 2. 创建DatagramSocket时候传入的端口是指定客户端自己在本机的端口 * 而不是服务器的端口注意和上面区分开 */publicclassClient{privateintport;// 服务器的端口privateStringaddr;// 服务器的地址privateDatagramSocketsocketnull;publicClient(intport,Stringaddr)throwsSocketException{this.portport;this.addraddr;socketnewDatagramSocket();// 让系统自动分配端口号}publicvoidstart()throwsIOException{System.out.println(客户端启动);ScannerscnewScanner(System.in);while(true){// 1. 构造请求数据报注意要传入目的端口和IP到数据报中System.out.print(请输入要发送给服务器的信息);Stringmessagesc.nextLine();DatagramPacketreqnewDatagramPacket(message.getBytes(),0,message.getBytes().length,InetAddress.getByName(addr),// 利用静态方法getByName构造InetAddressport);// 2. 发送请求到服务器socket.send(req);// 3. 接收服务器发来的响应然后进行解析DatagramPacketrespnewDatagramPacket(newbyte[4096],4096);socket.receive(resp);StringdatanewString(resp.getData(),0,resp.getLength());// 进行日志输出查看效果System.out.println(响应data);}}publicstaticvoidmain(String[]args)throwsIOException{ClientclientnewClient(8080,127.0.0.1);client.start();}}运行效果如下所示Ⅲ. TCP 套接字编程一、常用方法TCP连接只需要在创建套接字时候绑定端口和地址即可而不需要像UDP一样每次发送数据的时候都要指定目标端口和地址ServerSocket这个类主要负责建立连接、监听新连接而不负责数据的接收和发送Socket这个类主要负责数据的接收和发送因为TCP是面向字节流的所以实际上数据的接收和发送都是通过Socket获取套接字文件的输入输出流InputStream/OutputStream然后以字节为单位来处理该底层套接字本质还是文件IO。在Java中如果你没有显式调用connect()创建连接但你直接使用Socket.getOutputStream().write(...)来写数据则系统会在你第一次写数据的时候自动调用connect()建立连接方法 / 构造方法返回值类型功能说明ServerSocket()构造方法创建未绑定的服务器套接字ServerSocket(int port)构造方法创建并绑定到指定端口的套接字ServerSocket(int port, int backlog)构造方法指定端口与连接请求队列长度ServerSocket(int port, int backlog, InetAddress bindAddr)构造方法指定端口、队列长度和绑定地址accept()Socket阻塞等待客户端连接返回通信用的 Socketclose()void关闭服务器套接字释放资源isClosed()boolean判断服务器套接字是否关闭getInetAddress()InetAddress获取绑定的本地 IP 地址getLocalPort()int获取绑定的本地端口setSoTimeout(int timeout)void设置 accept() 阻塞的超时时间毫秒getSoTimeout()int获取当前 accept() 超时时间Socket()构造方法创建未连接的套接字用于延迟连接Socket(String host, int port)构造方法创建并连接到指定主机和端口Socket(InetAddress address, int port)构造方法同上使用 IP 地址连接getInputStream()InputStream获取输入流用于接收数据getOutputStream()OutputStream获取输出流用于发送数据close()void关闭连接释放资源isClosed()boolean判断是否关闭连接isConnected()boolean判断是否连接成功isBound()boolean判断是否已绑定本地地址getInetAddress()InetAddress获取远程地址getPort()int获取远程端口号getLocalAddress()InetAddress获取本地地址getLocalPort()int获取本地端口号setSoTimeout(int timeout)void设置输入流读取的超时时间getSoTimeout()int获取读取超时时间二、服务端监听新连接创建新线程来处理新连接Socket防止主线程阻塞读取请求并进行解析将解析后的请求进行业务处理响应结果给客户端关闭Socket防止资源泄露问题这里需要关闭Socket对象的原因是一个服务器会创建很多新线程来处理不同的连接这些连接本质都是套接字文件如果没有释放文件资源的话最后就会导致资源泄露问题至于ServerSocket和DatagramSocket为什么不需要释放是因为它们全局只有一个对象而且生命周期是随着程序生命周期的所以不会出现资源泄露问题此外Scanner和PrintWriter也不需要释放因为它们是从 Socket.getXXX() 获得的本质还是 Socket 对象套接字文件对应的流对象所以不需要关心 Scanner 和 PrintWriter 的释放问题注意事项因为Scanner这里使用的是nextLine()和hasNextLine()所以PrintWriter在使用的时候不能用write()而要用println()因为write()是不带换行符的此时就算回车结束了字符串也不会带回车那么进入判断语句中就卡在那里了结论用Scanner.nextLine()读取就一定要println()写入。在用PrintWriter写入数据到套接字文件后要调用flush()进行缓冲区刷新不然只能缓冲区快满了自动刷新① 多线程版本/** * 服务器只需要指定端口即可 */publicclassServer{privateServerSocketsocketnull;publicServer(intport)throwsIOException{socketnewServerSocket(port);}publicvoidstart()throwsIOException{System.out.println(TCP服务器启动);while(true){// 1. 监听新连接Socketconnsocket.accept();System.out.println(获取到新连接conn.getInetAddress()/conn.getPort());// 2. 创建新线程来处理新连接防止主线程阻塞newThread(()-{work(conn);}).start();}}// 新连接实际上要处理的任务privatevoidwork(Socketconn){try(InputStreaminconn.getInputStream();OutputStreamoutconn.getOutputStream();ScannerscnewScanner(in);PrintWriterpwnewPrintWriter(out)){while(true){// 3. 读取请求并进行解析if(sc.hasNextLine()false){// 要判断是否断开连接如果客户端断开连接了则会返回falseSystem.out.printf([%s:%d] 客户端下线\n,conn.getInetAddress().toString(),conn.getPort());break;}Stringreqsc.nextLine();// 4. 将解析后的请求进行业务处理Stringrespfunc(req);// 5. 响应结果给客户端pw.println(resp);// ✔自动添加换行符满足服务端 Scanner.nextLine()使用write则会死循环pw.flush();// ❗❗❗细节❗❗❗// 搞一下日志输出看看效果System.out.printf([%s:%d] req: %s, resp: %s\n,conn.getInetAddress().toString(),conn.getPort(),req,resp);}}catch(IOExceptione){thrownewRuntimeException(e);}finally{// 6. 释放Socket资源try{conn.close();}catch(IOExceptione){thrownewRuntimeException(e);}}}privateStringfunc(Stringdata){returndata;}publicstaticvoidmain(String[]args)throwsIOException{ServerservernewServer(9090);server.start();}}② 线程池版本只需要改动上面start()函数里面创建线程的方式即可publicvoidstart()throwsIOException{System.out.println(TCP服务器启动);while(true){// 监听新连接Socketconnsocket.accept();System.out.println(获取到新连接conn.getInetAddress()/conn.getPort());// 创建线程池来处理新连接推荐用newCachedThreadPoolExecutorServicepoolExecutors.newCachedThreadPool();pool.submit(()-{work(conn);});}}三、客户端输入数据写入Socket对象中然后进行刷新接收服务器的响应publicclassClient{privateSocketconnnull;publicClient(Stringaddr,intport)throwsIOException{connnewSocket(addr,port);}publicvoidstart(){System.out.println(客户端启动);ScannertmpnewScanner(System.in);try(InputStreaminconn.getInputStream();OutputStreamoutconn.getOutputStream();ScannerscnewScanner(in);PrintWriterpwnewPrintWriter(out)){while(true){// 1. 输入数据写入Socket中然后刷新System.out.print(请输入要发送的数据);Stringreqtmp.nextLine();pw.println(req);// ✔自动添加换行符满足服务端 Scanner.nextLine()使用write则会死循环pw.flush();// ❗❗❗细节❗❗❗// 2. 接收服务器的响应if(sc.hasNextLine()false){System.out.println(客户端断开连续);break;}Stringrespsc.nextLine();// 打印日志看看效果System.out.printf([%s:%d] req: %s, resp: %s\n,conn.getInetAddress().toString(),conn.getPort(),req,resp);}}catch(IOExceptione){thrownewRuntimeException(e);}}publicstaticvoidmain(String[]args)throwsIOException{ClientclientnewClient(127.0.0.1,9090);client.start();}}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询