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

 

posted @ 2021-11-11 14:43  不卷轮子锅  阅读(292)  评论(0编辑  收藏  举报