zoukankan      html  css  js  c++  java
  • java网络编程基础

    前言


      通过网络进行数据传输时,一般使用TCP/UDP进行数据传输。但是两个的区别就是TCP可靠,UDP不可靠。两个的共同之处就是都需要建立socket套接字,将IP地址和端口port进行绑定。但是服务器和客户端的socket是有点区别的,服务器端需要显示的指定端口号,以便进行数据监听;而客户端只需要指定IP就行,端口号则由操作系统来分配。

    基础类


     

    (1) InetAddress类

      该类就是表示互联网中的IP地址,常用的方法有:

    • getByName(String host) 静态方法,给定主机名来获取IP地址对象
    • getHostAddress()   获取主机的ip地址

    (2) InetSocketAddress类

      这个类一看就可socket有关,他就是用来创建socket套接字,将ip地址和端口进行绑定,主要的用法就是其构造器:

    •  InetSocketAddress(InetAddress addr, int port)  //如果addr等于null,则表示绑定本机的所有IP
    •  InetSocketAddress(String hostname,  int port)

    服务器端套接字


     

      这里只简述TCP套接字,我们先看看如果如何写一个简单的服务器,这里先用linux C来实现。

    #include "unp.h"
    #include <time.h>
    
    int main(int argc, char** argv){
        int listenfd, connfd;
        socketlen_t len;
        struct sockaddr_in servaddr, cliaddr;
        char buff[MAXLINE];
        time_t ticks;
    
        //选择协议族创建套接字3,这里是TCP族
        listenfd = Socket(AF_INET, SOCK_STREAM, 0);
        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        //将本机上所有的IP的都进行注册
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        //指定监听的端口号
        servaddr.sin_port = htons(31);
        //将赋值好结构体seraddr绑定到套接字上
        Bind(listenfd, (SA *)&servaddr, sizeof(servaddr));
        //打开端口监听,第二个参数表示未完成链接的最大个数(正在进行SYN传输)
        Listen(listenfd, LISTENQ);
        for(;;){
            len = sizeof(cliaddr);
            connfd = Accept(listenfd, (SA *)&cliaddr, &len);
            Write(connfd, buff, strlen(buff));
            Close(connfd);
        }
    }

    可以看到在用C实现一个TCP服务器时比较复杂,而java就相对简单一些。

    • java服务器
    package com.dy.xidian.net;
    
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Server {
        public static void main(String[] args) throws IOException {
            ServerSocket server = new ServerSocket(8888);
            Socket socket = server.accept();
            String msg = "欢迎使用";
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                    socket.getOutputStream()));
            bw.write(msg);
            bw.flush();
            bw.close();
        }
    }
    • java客户端
    package com.dy.xidian.net;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    public class Client {
        public static void main(String[] args) throws UnknownHostException,
                IOException {
            Socket client = new Socket("localhost", 8888);
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    client.getInputStream()));
            String echo = br.readLine();
            System.out.println(echo);
        }
    }

    分析java套接字


     

      ServerSocket server = new ServerSocket(8888); 

    我们先看ServerSocket实现方式,其调用了另一个套接字:

    public ServerSocket(int port) throws IOException {
            this(port, 50, null);
        }

    ServerSocket的重载函数,主要是用InetSocketAddress创建套接字并进行通过bind进行绑定

     public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
            setImpl();
            if (port < 0 || port > 0xFFFF)
                throw new IllegalArgumentException(
                           "Port value out of range: " + port);
            if (backlog < 1)
              backlog = 50;
            try {
                bind(new InetSocketAddress(bindAddr, port), backlog);
            } catch(SecurityException e) {
                close();
                throw e;
            } catch(IOException e) {
                close();
                throw e;
            }
        }

    在进行bind操作时,同时也调用的监听函数,这里只显示一部分

    public void bind(SocketAddress endpoint, int backlog) throws IOException {
            //TODO
            try {
                SecurityManager security = System.getSecurityManager();
                if (security != null)
                    security.checkListen(epoint.getPort());
                getImpl().bind(epoint.getAddress(), epoint.getPort());
                getImpl().listen(backlog);
                bound = true;
            } 
           // TODO
     }

     总结


     

      通过上面的观察,我们可以发现虽然java在进行网络编程中的代码相对比较简单,但是其内部的整个流程和C是一样的。对服务器而言都需要经历:创建套接字---绑定套接字----监听端口----接受请求。这个值得注意的是listen会将建立好的套接字(刚完成三次握手)放到一个缓冲队列中,而accept会从缓冲队列中取。由于缓冲队列可能满也可能空,所以listen会出现阻塞(表现为拒绝客户端的链接)。当缓冲区空的时候accept则会阻塞。

  • 相关阅读:
    uniapp解决图形验证码问题及arraybuffer二进制转base64格式图片
    uni-app图片上传接口联调
    Redis与Mysql双写一致性方案解析(转载)
    python 3 for循环倒序、一组数据参数解包
    python使用for循环打印直角三角形、菱形、乘法口诀,1至100的和、奇数和、偶数和
    使用jmeter做接口测试,简单实例
    python发送无参数get请求
    python的第三方库unittestreport 详细功能使用文档(V1.1.1)-转载
    python 3 发送邮件(转载)
    python使用apscheduler执行定时任务时报错:Run time of job "pr (trigger: cron[minute='25'], next run at: 2021-05-05 22:25:00 CST)" was missed by 0:00:01.185258
  • 原文地址:https://www.cnblogs.com/xidongyu/p/5498354.html
Copyright © 2011-2022 走看看