zoukankan      html  css  js  c++  java
  • Java 利用 sockert 实现TCP编程一

    实现目的,本来是要用Java实现一个TCP的代理服务器,这里首先实现利用serverSocket来实现TCP的通讯,然后再在这个基础上实现JAVA版本的代理。

    一  实现的业务逻辑过程:

    1.  服务端开启监听

    2. 客户端通过socket连接客户端

    3. 服务端接收到客户端连接后,开启一个线程单独处理每一个客户进程。

    二  业务代码

    服务端代码:  SocketServerTest.java 

    package com.example.demo;
    
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * @author freew
     */
    public class SocketServerTest {
        public static void main(String[] args) {
            try {
                //创建一个服务器端的Socket,即ServerSocket,绑定需要监听的端口
                ServerSocket serverSocket = new ServerSocket(8888);
                Socket socket = null;
                //记录连接过服务器的客户端数量
                int count = 0;
                System.out.println("***服务器即将启动,等待客户端的连接***");
                while(true){//循环侦听新的客户端的连接
                    //调用accept()方法侦听,等待客户端的连接以获取Socket实例
                    socket = serverSocket.accept();
                    //创建新线程
                    Thread thread = new Thread(new ServerThread(socket));
                    thread.start();
    
                    count++;
                    System.out.println("服务器端被连接过的次数:"+count);
                    InetAddress address = socket.getInetAddress();
                    System.out.println("当前客户端的IP为:"+address.getHostAddress());
                }
                //serverSocket.close();一直循环监听,不用关闭连接
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    线程处理器代码:ServerThread.java

    package com.example.demo;
    
    import java.io.*;
    import java.net.Socket;
    import java.net.SocketException;
    
    public class ServerThread implements Runnable {
    
        Socket socket = null;//和本线程相关的Socket
    
        public ServerThread(Socket socket) {
            this.socket = socket;
        }
      
        public String receiveData(Socket connection) {
            String buffer = "";
            try {
                connection.setSoTimeout(2000);
                InputStream is = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(is, "UTF8");
                BufferedReader br = new BufferedReader(isr);
                String data = null;
                while ((data = br.readLine()) != null) {//循环读取客户端的信息
                    buffer += data;
                }
            } catch (SocketException e) {
                //e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                //e.printStackTrace();
            } catch (IOException e) {
                //e.printStackTrace();
            }
    
            if (buffer.length() > 0) {
                buffer = "我是服务器,客户端提交信息为:" + buffer;
            }
            return buffer;
        }
    
        @Override
        public void run() {
            while (true) {
            //要注意这里,把收数据的代码单独拿出去是很有必要的,注意,这里是消息循环 String recevieData
    = receiveData(socket); if (recevieData.length() > 0) { System.out.println(recevieData); OutputStream os = null; try { os = socket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } //输出流包装为打印流 PrintWriter pw = new PrintWriter(os); //向服务器端发送信息 //写入内存缓冲区 pw.write(String.format("%s",recevieData+"\n")); pw.flush();//刷新缓存,向服务器端输出信息 } } } }

    客户端代码:SocketClientTest.java

    package com.example.demo;
    
    import java.io.*;
    import java.net.Socket;
    import java.net.SocketException;
    import java.net.UnknownHostException;
    import java.util.Random;
    import java.util.Scanner;
    
    /**
     * @author freew
     */
    public class SocketClientTest {
    
        public static String receiveData(Socket connection) {
            String buffer = "";
            try {
                connection.setSoTimeout(2000);
                InputStream is = connection.getInputStream();
                InputStreamReader isr = new InputStreamReader(is, "UTF8");
                BufferedReader br = new BufferedReader(isr);
                String data = null;
                while ((data = br.readLine()) != null) {//循环读取客户端的信息
                    buffer += data;
                }
            } catch (SocketException e) {
                //e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                //e.printStackTrace();
            } catch (IOException e) {
                //e.printStackTrace();
            }
    
            if (buffer.length() > 0) {
                buffer = "我是客服端,服务端提交信息为:" + buffer;
            }
            return buffer;
        }
    
    
        public static void main(String[] args) throws IOException {
            try {
                //创建客户端Socket,指定服务器地址和端口
                Socket socket = new Socket("localhost", 8888);
                String msg = "";
                while (true) {
                    Scanner scan = new Scanner(System.in);
                    // 从键盘接收数据// nextLine方式接收字符串
                    System.out.println("nextLine方式接收:");
                    // 判断是否还有输入
                    if (scan.hasNextLine()) {
                        String str2 = scan.nextLine();
                        System.out.println("输入的数据为:" + str2 + "\n");
    
                        //建立连接后,获取输出流,向服务器端发送信息
                        OutputStream os = socket.getOutputStream();
                        //输出流包装为打印流
                        PrintWriter pw = new PrintWriter(os);
                        //向服务器端发送信息 //写入内存缓冲区
                        pw.write(String.format("%s", str2 + "\n"));
                        pw.flush();//刷新缓存,向服务器端输出信息
    
                        msg = receiveData(socket);
                        if (msg.length() > 0) {
                            System.out.println(msg);
                        }
                    }
    
                    msg = receiveData(socket);
                    if (msg.length() > 0) {
                        System.out.println(msg);
                    }
                }
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
    }

    注意:上面的红色部分,这里要添加两次读出入流的操作,是为了输入后,很快就能看到服务端的返回消息。

    三  测试。

    启动服务端,监听 8888 

     启动客户端:连接  8888

     客户端输入:第一个消息  回车

    此时服务端接收的消息为:

     马上切换到客户端查看返回的消息:

     可以继续输入。

    四  一些坑

    1. 在java中,直接通过SOCKET进行连接,发送消息时,消息的末尾一定要加上 \n 回车符,否则,socket会认为消息还没有发完,于是就会发现,好像客户端发送了消息,服务端切收不到消息的情况。这时候真实的原因是客户端的消息其实是没有发出的。

    2. 这里没有使用线程池,实际测试过程中,发现每次启动一个线程来处理,消息发送的效率不高。

    半斤八两开始写BLOG了
  • 相关阅读:
    node代码打包为 exe文件---端口进程关闭demo
    java 中几种常用数据结构
    Java 多线程编程
    【java排序】 归并排序算法、堆排序算法
    【java排序】 选择排序,插入排序,希尔算法
    【java排序】冒泡排序、快速排序
    springMVC执行流程及原理
    Java反射机制详解
    【Java并发编程】:并发新特性—信号量Semaphore
    【Java并发编程】:并发新特性—障碍器CyclicBarrier
  • 原文地址:https://www.cnblogs.com/freewsf/p/15539876.html
Copyright © 2011-2022 走看看