Java学习——Socket网络编程

天行健,君子以自强不息。 ——《周易》

前言:学习内容,略显粗浅。

准备:IDEA打开多个控制台窗口运行程序

一、ip地址和端口

1.ip地址

在网络中每台计算机都必须有一个的IP地址;
32位,4个字节,常用点分十进制的格式表示,例如:192.168.1.100
127.0.0.1 是固定ip地址,代表当前计算机,相当于面向对象里的 “this”

2.端口

两台计算机进行连接,总有一台服务器,一台客户端。
服务器和客户端之间的通信通过端口进行。
如图:
ip地址是 192.168.1.100的服务器通过端口 8080
与ip地址是192.168.1.189的客户端 的1087端口通信

在这里插入图片描述

3.获取本机IP地址
public static void main(String[] args) throws UnknownHostException {
        InetAddress host = InetAddress.getLocalHost();
        String ip =host.getHostAddress();
        System.out.println("本机ip地址:" + ip);
    }
4.ping命令

使用ping判断一个地址是否能够到达
ping不是java的api,是windows中的一个小工具,用于判断一个地址的响应时间

如图:

在这里插入图片描述

5.使用java 执行ping命令

借助 Runtime.getRuntime().exec() 可以运行一个windows的exe程序

//获取IP
        InetAddress host = InetAddress.getLocalHost();
        String ip =host.getHostAddress();
        System.out.println("本机ip地址:" + ip);
        //访问ping
        Process p = Runtime.getRuntime().exec("ping "+ ip);
        //字符流读取信息
        BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(),"gbk"));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            if (line.length() != 0)
                sb.append(line + "\r\n");
        }
        System.out.println("本次指令返回的消息是:");
        System.out.println(sb.toString());

二、Socket

socket是BSD UNIX的通信机制,通常称为“套接字”,其英文原意是“孔”或“插座”。有些顾名思义,socket正如其英文原意一样,像是一个多孔插座,可以提供多个端口的连接服务。

工作原理:

对于服务器来说:服务器先初始化socket,然后端口绑定(bind),再对端口监听(listen),调用accept阻塞,等待客户端连接请求。

对于客户端来说,客户端初始化socket,然后申请连接(connection)。

涉及到TCP三次握手

  • 1.客户端发送连接申请

  • 2.服务端收到申请,并回复申请许可

  • 3.客户端收到申请许可,并回应自己收到了,然后两边就可以开始发送数据了

1.建立连接

先运行Server,再运行Client

实践代码,搓搓小手动起来(=!=):

服务端Server

package priv.study.network2;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) {
        try {
            //服务端打开端口8888
            ServerSocket ss = new ServerSocket(8888);
            //在8888端口上监听,看是否有连接请求过来
            System.out.println("监听在端口号:8888");
            Socket s =  ss.accept();
            System.out.println("有连接过来" + s);

            s.close();
            ss.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


客户端Client

package priv.study.network2;

import java.io.IOException;
import java.net.Socket;

public class Client {
    public static void main(String[] args) {
        //连接到本机的8888端口
        try {
            Socket s = new Socket("127.0.0.1",8888);
            System.out.println(s);
            s.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.发送数字
package priv.study.network2;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server1 {
    public static void main(String[] args) {

        try {
            //服务端打开8888端口
            ServerSocket ss = new ServerSocket(8888);
            //监听在端口8888
            System.out.println("监听在端口号:8888");
            Socket s =  ss.accept();
            //读取客户端发送的消息
            InputStream is = s.getInputStream();
            int msg = is.read();
            System.out.println("客户端来消息了:" +msg );

            //用完关闭
            is.close();
            s.close();
            ss.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package priv.study.network2;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client1 {
    public static void main(String[] args) {
        try {
            //客户端连接端口8888
            Socket s = new Socket("127.0.0.1", 8888);
            //输出数字100到服务端
            OutputStream os = s.getOutputStream();
            os.write(100);
            //关闭
            os.close();
            s.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.发送字符串

直接使用字节流收发字符串比较麻烦,使用数据流对字节流进行封装,这样收发字符串就容易了

  1. 把输出流封装在DataOutputStream中
    使用writeUTF发送字符串 “Legendary!”
  2. 把输入流封装在DataInputStream
    使用readUTF读取字符串,并打印
package priv.study.network2;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server2 {
    public static void main(String[] args) {
        try {
            //服务端打开8888端口
            ServerSocket ss = new ServerSocket(8888);
            //监听在端口8888
            System.out.println("监听在端口号:8888");
            Socket s =  ss.accept();
            //读取客户端发送的字符串
            //把输入流封装在DataInputStream
            InputStream is = s.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            String msg = dis.readUTF();
            System.out.println("客户端来消息了:" +msg );

            //用完关闭
            dis.close();
            s.close();
            ss.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package priv.study.network2;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client2 {
    public static void main(String[] args) {
        try {
            //客户端连接端口8888
            Socket s = new Socket("127.0.0.1", 8888);
            //输出字符串到服务端
            //把输出流封装在DataOutputStream中
            OutputStream os = s.getOutputStream();
            DataOutputStream dos = new DataOutputStream(os);
            //使用Scanner读取控制台的输入,并发送到服务端
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入:");
            String str = sc.next();
            //使用writeUTF发送字符串
            dos.writeUTF(str);
            //关闭
            dos.close();
            s.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

三、多线程聊天

如果使用单线程开发Socket应用,那么同一时间,要么收消息,要么发消息,不能同时进行。

为了实现同时收发消息,就需要用到多线程。
这是因为接受和发送都在主线程中,不能同时进行。 为了实现同时收发消息,基本设计思路是把收发分别放在不同的线程中进行

  1. SendThread 发送消息线程
  2. RecieveThread 接受消息线程
  3. Server一旦接受到连接,就启动收发两个线程
  4. Client 一旦建立了连接,就启动收发两个线程
package priv.study.network2;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

public class RecieveThread extends Thread{
    private Socket s;

    public RecieveThread(Socket s) {
        this.s = s;
    }

    @Override
    public void run() {
        try {
            InputStream is = s.getInputStream();

            DataInputStream dis = new DataInputStream(is);
            while (true) {
                String msg = dis.readUTF();
                System.out.println(msg);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

package priv.study.network2;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class SendThread extends Thread{
    private Socket s;

    public SendThread(Socket s) {
        this.s = s;
    }

    @Override
    public void run() {
        try {
            OutputStream os = s.getOutputStream();
            DataOutputStream dos = new DataOutputStream(os);
            while (true) {
                Scanner sc = new Scanner(System.in);
                String str = sc.next();
                dos.writeUTF(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    }
package priv.study.network2;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server3 {
    public static void main(String[] args) {
        try {

            ServerSocket ss = new ServerSocket(8888);

            System.out.println("监听在端口号:8888");
            Socket s = ss.accept();

            //启动发送消息线程
            new SendThread(s).start();
            //启动接受消息线程
            new RecieveThread(s).start();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
    }


package priv.study.network2;

import java.io.*;
import java.net.Socket;

public class Client3 {
    public static void main(String[] args) {
        try {
            Socket s = new Socket("127.0.0.1", 8888);

            // 启动发送消息线程
            new SendThread(s).start();
            // 启动接受消息线程
            new RecieveThread(s).start();

        }  catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

还想了解更多:Java自学网站

今天学习分享的内容到此为止了,本是想要激励自己学下去,但发现快乐更是知识在于分享!
作为初学者对于Java的理解实在浅薄,如有错误请指正,万分感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值