java 网络编程

概述

计算机网络:
是指将地理位置不同的具有独立功能的多台计算机及外部设备,通过通信线路链接起来,在网络操作系统,网络管理软件及网络通讯协议,的管理和协调下,实现资源共享和信息传递的计算机系统

网络编程:
是指就是用来实现,不同计算机上运行的程序间可以进行数据交换

网络模型
计算机间用那种规则进行通信,就是网络模型研究的问题,网络模型一般指
这里写图片描述

网络七层概述

1.物理层: 主要定义物理设备的标准,如网线的接口类型,各种传输介质的传输率,他的主要作用是传输比特流,(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。

2. 数据链路层:主要将从物理层接收到的数据,进行MAC地址(网卡的地址)的封装和解封装,长把这一层的数据叫做帧,这一层工作的设备叫做交换机,数据通过交换机进行传输

3. 网络层: 主要将从下层接收的数据,进行IP地址的封装和解封装,在这一层工作的设备叫做路由器,长把这一层的数据叫做数据包

4. 传输层: 定义了一些传输数据的协议和端口号。如 TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求较高的,数据量大的数据) UDP(用户数据报协议,与TCP协议恰恰相反,用于传输可靠性要求不高,数据量小的数据),主要是从下层接收到的数据,进行分段和传输,到达目的地址后,在进行重组,常常把这一层的数据叫做段

5.会话层: 通过传输层(端口号:传输端口和接收端口)建立数据传输的通道,主要在你的系统之间发起会话或者接收会话(设备之间需要互相认识,可以通过ip也可以是MAC或者是主机名)

6.表示层: 主要是对接收的数据进行解释,加密与解密,压缩和解压缩,等(也就是吧计算机能看懂的东西,转换成人能够看懂的东西)

7.应用层: 主要是一些终端应用,比如 QQ,浏览器这类的(可以把它理解成我们在电脑屏幕上看到的东西,就是终端应用)

这里写图片描述

网络编程三要素

发送信件我们需要有三点,才能保证发送信件的成功
1 收件人地址 (ip)
2 收件人(端口)
3 信的内容,双方都可以看懂(协议)

IP

1.IP:计算机在互联网上的唯一地址;
  		192.168.0.100:四段0--255的数据组成(IPv4):点分十进制
  		IP地址的范围:
  		最小IP地址:000.000.000.000:
  		最大IP地址:255.255.255.255:
  	A:所谓IP地址就是给每个连接在Internet上的主机分配的一个32bit地址。按照TCP/IP规定,IP地址用二进制来表示,
     每个IP地址长32bit,比特换算成字节,就是4个字节。
     例如一个采用二进制形式的IP地址是“11000000101010000000000101100100”,
     这么长的地址,人们处理起来也太费劲了。
     为了方便人们的使用,IP地址经常被写成十进制的形式,中间使用符号“.”分开不同的字节。
     于是,上面的IP地址可以表示为“10.0.0.1”。IP地址的这种表示法叫做“点分十进制表示法”,这显然比1和0容易记忆得多。

	B:IP地址的组成
	IP地址 = 网络号码+主机地址

	A类IP地址:第一段号码为网络号码,剩下的三段号码为本地计算机的号码:192.168.0.100:192是网络号码
	B类IP地址:前二段号码为网络号码,剩下的二段号码为本地计算机的号码
	C类IP地址:前三段号码为网络号码,剩下的一段号码为本地计算机的号码
	
	以下三个IP地址:
	1).192.168.0.100;
	2).192.168.0.200;
	3).192.168.1.100;
	请问以上三个IP地址哪些可以互相访问?关键取决于"子网掩码":
	如果子网掩码:255.255.255.0
	          11111111.11111111.11111111.00000000(子网掩码中,全部是1端被标识为"网络号码")
	                           此时:1)和2)可以互相访问;
	如果子网掩码:255.255.0.0
			  11111111.11111111.00000000.00000000
			    此时:1)和2)和3)都可以互访;

	特殊地址:
	127.0.0.1 回环地址,可用于测试本机的网络是否有问题. ping 127.0.0.1   

	DOS命令 ipconfig:查看本机IP地址

	xxx.xxx.xxx.0 网络地址
	xxx.xxx.xxx.255 广播地址

	A类	1.0.0.1---127.255.255.254	(1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址)							(2)127.X.X.X是保留地址,用做循环测试用的。
	B类	128.0.0.1---191.255.255.254	172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。
	C类	192.0.0.1---223.255.255.254	192.168.X.X是私有地址
	D类	224.0.0.1---239.255.255.254 	
	E类	240.0.0.1---247.255.255.254	

端口

1).物理端口:网卡口;
  		2).逻辑端口:
  			1>.由操作系统维护的;
  			2>.Windows的逻辑端口范围:0--65535
  			3>.其中0--1024一般由系统内部使用,我们尽量不要使用;
  			4>.一个网络应用程序,至少要占用一个端口,可以同时占用多个端口;
              一个端口,在同一时刻,只能由一个应用程序占用;

这里写图片描述
协议

3.协议:TCP,UDP,FTP,HTTP....
  		1).UDP协议:
  			1.数据打包发送;
  			2.数据包大小有限制,最大64K;
  			3.面向无连接的(发送信息时,可以没有接收端);
  			     所以不安全的;
  			类似于:电视信号、广播信号;
  		2).TCP协议:
  			1.数据流发送数据;
  			2.数据大小无限制;
  			3.面向连接的(发送信息时,必须要有接收方)
  			类似于:打电话;
  			三次握手确保链接的建立:1 客户端 请求链接
						  		2 服务端 确定授予
						  		3 客户端 收到

InetAddress

  java.net.InetAddress(类):
  IP 地址是 IP 使用的 32 位或 128 位无符号数字,它是一种低级协议,UDP 和 TCP 协议都是在它的基础上构建的。
  成员方法:
  静态方法:
  	获取任意主机:static InetAddress getByName(String pcName):
  	获取自己主机: static InetAddress getLocalHost();
  普通方法:
  	主机名:getHostName
  	主机Ip地址:getHostAddress
InetAddress localHost = InetAddress.getLocalHost();
Log.d("mmm", localHost.getHostName() + "/" + localHost.getHostAddress());

看下Log

09-04 10:41:07.902 11774-11867/com.example.jh.rxhapp D/mmm: localhost/127.0.0.1

Socket

两台计算机如何通信

Socket套接字:
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
Socket原理机制:
通信的两端都有Socket。
网络通信其实就是Socket间的通信。
数据在两个Socket间通过IO传输。

这里写图片描述

UDP发送数据

public class UdpClient extends Thread {
    /*
     * UDP的发送端:
     *
     * 1.实例化一个DatagramSocket对象;
     * 2.准备数据:
     * 		1).目标IP--InetAddress对象
     * 		2).目标端口;
     * 		3).信息内容--byte[]数组
     * 3.实例化一个数据包对象:DatagramPacket对象
     * 4.调用DatagramSocket对象的方法,将数据包发送出去;
     */

    @Override
    public void run() {
        //实例化一个DatagramSocket对象
        DatagramSocket datagramSocket = null;
        try {
            datagramSocket = new DatagramSocket();
        } catch (SocketException e) {
            e.printStackTrace();
            Log.d("mmm", "服务器连接失败");
        }
        //准备数据
        InetAddress ip = null;
        try {
            ip = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
            Log.d("mmm", "未找到服务器");
        }
        int port = 8888;
        byte[] bytes = "UDP发送的数据,请接收".getBytes();
        //实例化DatagramPacket对象
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, ip, port);
        //发送数据
        try {
            datagramSocket.send(datagramPacket);
        } catch (IOException e) {
            e.printStackTrace();
            Log.d("mmm", "消息发送失败");
        }
        //释放资源
        datagramSocket.close();

        Log.d("mmm", "发送完毕");

    }
}
public class UdpServer extends Thread {
    /*
     * 接收端:
     *
     * 1.实例化一个DatagramSocket(端口):
     * 2.准备一个空的byte[]数组,用于接收数据;
     * 	   准备一个空的数据包对象:DatagramPacket
     * 3.调用DatagramSocket的方法接收数据;
     * 4.从DatagramPacket中解析数据;
     * 5.释放资源
     */

    @Override
    public void run() {

        try {
            //实例化一个DatagramSocket,带端口
            DatagramSocket datagramSocket = new DatagramSocket(8888);
            //创建一个空的byte数组
            byte[] bytes = new byte[1024];
            //准备一个空的DatagramPacket
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
            Log.d("mmm", "服务端启动等待接收数据");
            //接收数据
            datagramSocket.receive(datagramPacket);
            Log.d("mmm", "服务端接收数据完毕");
            //解析数据
            String ip = datagramPacket.getAddress().getHostAddress();
            byte[] data = datagramPacket.getData();
            String s = new String(data, 0, data.length);
            Log.d("mmm", "接收到IP:" + ip + "接收到数据:" + s);

            //释放资源
            datagramSocket.close();

        } catch (Exception e) {
            e.printStackTrace();
            Log.d("mmm", "接收异常");

        }
    }
}

public class UDPActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_udp);
        new UdpServer().start();

        findViewById(R.id.udp_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new UdpClient().start();
            }
        });
    }
}

看下log

09-04 11:56:12.062 14425-14546/com.example.jh.rxhapp D/mmm: 服务端启动等待接收数据
09-04 11:56:13.930 14425-14572/com.example.jh.rxhapp D/mmm: 发送完毕
09-04 11:56:13.930 14425-14546/com.example.jh.rxhapp D/mmm: 服务端接收数据完毕
09-04 11:56:13.930 14425-14546/com.example.jh.rxhapp D/mmm: 接收到IP:127.0.0.1接收到数据:UDP发送的数据,请接收

Tcp基本使用

public class TcpClient extends Thread{
    /*
     * TCP发送端:
     *
     * 1.实例化一个Socket对象,要指定IP和端口;
     * 2.如果要发送数据,通过Socket对象获取输出流:OutputStream
     * 3.输出数据;
     * 4.释放资源:
     */
    @Override
    public void run() {
        try {
            //实例化一个Scoket对象,指定ip和端口
            Socket socket = new Socket("127.0.0.1", 8888);
            //获取发送数据的输出流
            OutputStream outputStream = socket.getOutputStream();
            //输出数据
            outputStream.write("我是TCP发送数据".getBytes());
            //释放资源
            socket.close();
            Log.d("mmm","客户端发送完毕");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
public class TcpServer extends Thread {
    /*
     * TCP接收数据:
     *
     * 1.实例化一个ServerSocket,并指定端口号;
     * 	 调用ServerSocket的accept()方法等待连接:
     * 2.由于要读取数据,所以通过ServerSocket对象获取"输入流"--InputStream
     * 3.读取信息;
     * 4.释放资源;
     */
    @Override
    public void run() {
        //实例化一个实例化一个ServerSocket,并指定端口
        try {
            ServerSocket serverSocket = new ServerSocket(8888);
            //调用serverSocket的accept方法,等待连接
            Log.d("mmm", "等待连接");
            Socket socket = serverSocket.accept();
            Log.d("mmm", "有用户连接");
            //获取输入流读取数据
            InputStream inputStream = socket.getInputStream();
            //读取信息
            byte[] bytes = new byte[1024];
            int len = inputStream.read(bytes);
            String s = new String(bytes, 0, len);
            Log.d("mmm", s);
            //释放资源
            serverSocket.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

调用
public class TCPActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tcp);
        new TcpServer().start();

        findViewById(R.id.tcp_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new TcpClient().start();
            }
        });
    }
}

看下log

09-08 14:32:03.415 6654-6842/com.example.jh.rxhapp D/mmm: 等待连接
09-08 14:32:06.067 6654-6842/com.example.jh.rxhapp D/mmm: 有用户连接
09-08 14:32:06.068 6654-6842/com.example.jh.rxhapp D/mmm: 我是TCP发送数据
09-08 14:32:06.070 6654-6879/com.example.jh.rxhapp D/mmm: 客户端发送完毕

Tcp实现聊天功能


public class TcpChatClient extends Thread {

    private final Handler mHandler;
    private OutputStream mOutputStream;
    private Socket mSocket;

    public TcpChatClient(Handler handler) {
        this.mHandler = handler;
    }

    /*
         * TCP发送端:
         *
         * 1.实例化一个Socket对象,要指定IP和端口;
         * 2.如果要发送数据,通过Socket对象获取输出流:OutputStream
         * 3.输出数据;
         * 4.不断读取数据
         */
    @Override
    public void run() {

        try {
            //实例化一个Socket
            mSocket = new Socket("127.0.0.1", 8888);
            //获取输出流
            mOutputStream = mSocket.getOutputStream();
            //发送消息
            sendMessage("客户端请求链接");
            //获取输入流
            InputStream inputStream = mSocket.getInputStream();
            byte[] bytes = new byte[1024];
            int len = 0;
            //不断的读取数据
            while (true) {
                len = inputStream.read(bytes);
                String msg = new String(bytes, 0, len);
                Message msg1 = new Message();
                msg1.obj = "客户端收到:" + msg;
                mHandler.sendMessage(msg1);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送消息
     *
     * @param message
     */
    public void sendMessage(String message) {
        try {
            mOutputStream.write(message.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void colseSocket() {
        try {
            mSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



public class TcpChatServer extends Thread {

    private final Handler mHanlder;
    private Socket mSocket;
    private OutputStream mOutputStream;

    public TcpChatServer(Handler handler) {
        this.mHanlder = handler;
    }

    /*
            * TCP接收数据:
            *
            * 1.实例化一个ServerSocket,并指定端口号;
            * 	 调用ServerSocket的accept()方法等待连接:
            * 2.由于要读取数据,所以通过ServerSocket对象获取"输入流"--InputStream
            * 3.读取信息;
            * 4.获取输出流,发送消息
            */
    @Override
    public void run() {
        try {
            //实例化ServerSocket
            ServerSocket serverSocket = new ServerSocket(8888);
            //等待链接
            Log.d("mmm", "服务器等待链接");
            mSocket = serverSocket.accept();
            Log.d("mmm", "链接成功");
            //获取书输入流
            InputStream inputStream = mSocket.getInputStream();
            //获取输出流
            mOutputStream = mSocket.getOutputStream();
            //读取消息
            byte[] bytes = new byte[1024];
            //不断的读取数据
            while (true) {
                int len = inputStream.read(bytes);
                String s = new String(bytes, 0, len);
                Message msg = new Message();
                msg.obj = "服务端收到:"+s;
                mHanlder.sendMessage(msg);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 发送消息
     * @param msg
     */
    public void sendMessage(String msg) {
        try {
            mOutputStream.write(msg.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


public class TcpChatClientActivity extends AppCompatActivity {

    private TextView mTextView;
    private EditText mEditText;
    private Button mClient;
    private Button mServer;
    private StringBuffer mStringBuffer;


    public Handler handler = new Handler() {
        @Override
        public void dispatchMessage(Message msg) {
            String mssage = (String) msg.obj;
            mStringBuffer.append("\n" + mssage);
            mTextView.setText(mStringBuffer);
        }
    };
    private TcpChatServer mTcpChatServer;
    private TcpChatClient mTcpChatClient;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tcp_chat_client);
        initView();
        mTcpChatServer = new TcpChatServer(handler);
        mTcpChatServer.start();
        mTcpChatClient = new TcpChatClient(handler);
        mTcpChatClient.start();
    }

    private void initView() {
        mTextView = (TextView) findViewById(R.id.tcp_chat_text);
        mEditText = (EditText) findViewById(R.id.tcp_chat_edit);
        mClient = (Button) findViewById(R.id.tcp_chat_button);
        mServer = (Button) findViewById(R.id.tcp_chat_button1);
        mStringBuffer = new StringBuffer();
        mClient.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final String trim = mEditText.getText().toString().trim();
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        mTcpChatClient.sendMessage(trim);
                    }
                };
                mEditText.setText("");
                Thread thread = new Thread(runnable);
                if (thread.isAlive()) {
                    thread.run();
                } else {
                    thread.start();
                }

                hideSoftInput();
            }
        });
        mServer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final String trim = mEditText.getText().toString().trim();
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        mTcpChatServer.sendMessage(trim);
                    }
                };
                mEditText.setText("");
                Thread thread = new Thread(runnable);
                if (thread.isAlive()) {
                    thread.run();
                } else {
                    thread.start();
                }

                hideSoftInput();
            }
        });
    }

    public void hideSoftInput() {
        InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
    }
}

实现之后的大概样子是这样的
这里写图片描述

这个是在本机上测试的,当然也可以在不同手机上测试,只要确定俩个手机ip网段相同,可以互相访问就可以了

代码已上传GitHub https://github.com/renxh4/RXHApp 欢迎star

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值