Socket编程基础--基于TCP协议的网络编程

一、概述

在学习TCP协议之前,需要了解网络编程中的几个基本概念。

  • IP协议:是Internet Protocol的外语缩写,为计算机网络相互连接进行通信而设计的协议。在因特网中,它是能使连接到网上的所有计算机网络实现相互通信的一套规则,规定了计算机在因特网上进行通信时应当遵守的规则。任何厂家生产的计算机系统,只要遵守IP协议就可以与因特网互连互通。IP地址具有唯一性。
  • TCP协议:TCP协议被称作是一种端对端协议。它提供IP环境下的数据可靠传输,提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送
  • 端口号Port:主要是计算机用来来区分连接不同应用程序。注意:0-1023不可以使用,系统已经占用。

二、Java的基本网络支持

  • 使用InetAddress
  • URLDecoder和URLEncoder
  • URL、URLConnetction(这个后面说)

    InetAddress的简单使用

 public static void main(String[] args) throws Exception {
        InetAddress ia = InetAddress.getLocalHost() ;
        System.out.println("ip:" + ia.getHostAddress());
        System.out.println("主机名:" + ia.getHostName());
    }

URLDecoder和URLEncoder

URLDecoder和URLEncoder是完成字符串和application/x-www-form-urlencode MIME字符串之间的相互转化

  • URLDecoder的decode()方法可以将一个看上去是乱码的转换成不是乱码的字符串
  • URLEncoder的encode()方法可以将一个看上去不是乱码的转换成是application/x-www-form-urlencode MIME的字符串
public static void main(String[] args) throws Exception {
        String keyword = URLEncoder.encode("李文");
        System.out.println(keyword);
        keyword = URLDecoder.decode(keyword) ;
        System.out.println(keyword);
    }

三、通信流程

服务端

计算机能够接受通信实体请求的类是ServerSocket,ServerSocket用来监听客户端对应的socket,一般我们在while(true)里使用ServerSocket不断的获取socket,如果没用连接它会处于等待状态。

常用api:

  • accept():获取一个客户端socket的连接请求,这个方法会返回一个与客户端对应的socket,否则会处于等待状态,线程阻塞。
  • ServerSocket(int port):用指定端口号创建一个ServerSocket该值可以在0-65535之间。上面已经提过,0-1023不要用。
  • ServerSocket(int port,int backlog):增加一个改变连接队列长度的参数。
 //1.创建socketserver,监听3000端口
        ServerSocket ss = new ServerSocket(30000) ;
        while(true){
            Socket s = ss.accept();
            //2.将输出流包装成PrintStream
            PrintStream ps = new PrintStream(s.getOutputStream()) ;
            //3.进行IO操作
            ps.println("hello socket,i am from SocketServer");
            //4.关流
            ps.close(); 
            s.close() ;
        }

客户端

客户端通常使用Socket的构造器连接指定服务器
构造函数如下:
public Socket(String host, int port)
使用如下:

//1.创建socket
        Socket s = new Socket("127.0.0.1",30000) ;
        BufferedReader br = new BufferedReader(new      InputStreamReader(s.getInputStream())) ;
        String line = br.readLine();
        System.out.println("来自服务端:" + line );
        s.close() ;

上面的127.0.0.1是连接本地IP的。大家可以到C:\Windows\System32\drivers\etc这个目录下的host文件中查看到。
上面程序运首先要运行服务端,然后在运行客户端就可以进行通信了。
当服务端、客户端连接到了对应的socket之后,程序就不用再区分服务端、客户端了,两者是通过各自的socket通信。socket通过如下两个api来获取输出流、输入流。

 public InputStream getInputStream()
 public OutputStream getOutputStream() 

四、加入多线程

上面的client、server只是简单的通信,下面实现一个包含多线程的socket通信。我们在服务端创建多线程线程,每一个socket对应一个线程,这个线程负责读取socket输入流中的内容,也就是从客户端发送过来的数据,然后再返回给客户端信息表示收到了。

服务端代码:

    public static ArrayList<Socket> socketList = new ArrayList<Socket>() ;

    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket(30001) ;
        while(true){
            Socket s = ss.accept() ;
            //每次获取一个socket,添加到集合中
            socketList.add(s) ;
            //开启线程执行任务
            new Thread(new ServerThread(s)).start();
        }
    }

服务端创建一个集合用来存放来自客户端的Socket,每当获取一个socket,就开始启动一个线程,该线程用来处理通信业务。

class ServerThread implements Runnable{
    //处理的socket
    Socket s = null ;
    //处理socket对应的流
    BufferedReader br = null ;
    public ServerThread(Socket s ) throws IOException{
        this.s = s ;
        br = new BufferedReader(new InputStreamReader(s.getInputStream())) ;
    }

    public void run() {
        String context ;
        while((context=readFromClient())!= null ){
            for (Socket s : MyServer.socketList) {
                System.out.println("服务端收到数据了:" + context );
                PrintStream ps;
                try {
                    ps = new PrintStream(s.getOutputStream());
                    ps.println(context + "---来自服务端");
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    public String readFromClient(){
        try {
            return br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            //删除socket
            MyServer.socketList.remove(s);
        } 
        return null ;
    }
}

客户端代码:

public static void main(String[] args) {
        //1.创建socket
        try {
            Socket s = new Socket("127.0.0.1",30001) ;
            //2.获取来自服务端的数据
            new Thread(new ClientThread(s)).start() ;
            //3.获取socket对应的输出流
            PrintStream ps = new PrintStream(s.getOutputStream()) ;
            String line = null ;
            //4.键盘输入
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
            while((line = br.readLine())!= null ){
                //5.将键盘输入写到socket输出流中
                ps.println(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

重要的地方已经注释,代码不同,相信能看懂。这样就完成了多线程的通信了,还是和上面一样,先运行server,再运行client,通过运行可以知道每个客户端可以看到其它客户端的信息。

Ok,这篇已经结束了,这篇只是简单介绍了Socket的基础,后面会继续详细分析还有介绍基于UDP网络编程。

源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值