烦人的socket通信

需求是用户通过一个外网的ip和端口发送数据,我需要在服务器端接收并保存下来

第一个坑是外网端口对应的内网端口3369需要自己用nginx配置,之前用项目的nginx的配置模仿着写了一下,但是服务器卡在accept那里,好像是没有接收到请求,所以觉得应该是nginx转发请求有问题,可能配置出错了,后来运维帮忙改了下配置,的确似乎可以,虽然在报错,但是客户发送到请求好像能看到。。报错信息如下:

java.lang.IllegalArgumentException: Invalid character found in method name [{"ygdd":226169.99999999997,"deviceid":10000000000300,"timestamp":1670407934565}...]. HTTP method names must be tokens
        at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:419) ~[tomcat-embed-core-9.0.65.jar!/:na]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:271) ~[tomcat-embed-core-9.0.65.jar!/:na]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.65.jar!/:na]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) [tomcat-embed-core-9.0.65.jar!/:na]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) [tomcat-embed-core-9.0.65.jar!/:na]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.65.jar!/:na]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.65.jar!/:na]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.65.jar!/:na]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.65.jar!/:na]
        at java.lang.Thread.run(Unknown Source) [na:1.8.0_201]

一开始我的配置是http的配置:

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
	client_max_body_size 30m;

    server {
        listen       3369;
        server_name  localhost;

		
		location /energy{
		    proxy_set_header   X-Forwarded-Proto $scheme;
		    proxy_set_header   Host             $host;
		    proxy_set_header REMOTE-HOST $remote_addr;
                    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
		    proxy_set_header   X-Real-IP         $remote_addr;
		    proxy_connect_timeout   5000;
                    proxy_send_timeout      5000;
                    proxy_read_timeout      5000;
		    proxy_pass http://192.168.XX.XX:8803;
		}
    }
}

这个是http请求的配置,但其实我应该是tcp请求,所以这个配置根本就不行

别人修改的配置:

stream {
    log_format proxy '$remote_addr [$time_local] '
                 '$protocol $status $bytes_sent $bytes_received '
                 '$session_time "$upstream_addr" '
                 '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
	upstream cloudsocket {
		hash $remote_addr consistent;
		server 192.168.XX.XX:8803 weight=5 max_fails=3 fail_timeout=30s;
	}
	server {
	    error_log       logs/error_3369.log;
		access_log      logs/access_3369.log proxy;
		listen 3369;
		proxy_connect_timeout 10s;
		proxy_timeout 300s;
		proxy_pass cloudsocket;
	}
}

这个是处理tcp请求的,网上很多介绍tcp请求和http请求的,我到现在都很懵,怎么判断是客户端请求是tcp请求还是http请求呢。。之后再找吧,懒得管了。。

然后就是代码部分,逻辑是,外网ip加外网端口3369发送请求,外网端口3369对应的内网端口也是3369,nginx里配置了对3369的监听,会转发请求到远程的远程服务器,也就是192.168.XX.XX:8803,这个8803一定不要误会,不是要指定的tomcat的端口,是最后要监听的端口,服务器端的代码里要监听的是8803,而不是3369。。这是一直卡在accept的原因,因为压根的确没收到请求。。

server端:

package energy_use;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
	
	
	public static final int port = 8803;   
//    public static final String host = "139.198.177.XX";
    public static void main(String[] args) {    
        System.out.println("Server...\n");    
        Server server = new Server();    
        server.init();    
    }    
    
    
    
    public void init() {    
        try {    
            //创建一个ServerSocket,这里可以指定连接请求的队列长度  
            //new ServerSocket(port,3);意味着当队列中有3个连接请求是,如果Client再请求连接,就会被Server拒绝 
            ServerSocket serverSocket = new ServerSocket(port);    
          	 System.out.println("00000");
            while (true) {    
             	 System.out.println("010101010101");
                //从请求队列中取出一个连接
                Socket client = serverSocket.accept();    
            	 System.out.println("0");
                // 处理这次连接    
                new HandlerThread(client);    
            }    
        } catch (Exception e) {    
            System.out.println("服务器异常: " + e.getMessage());    
        }    
    }    
 
    private class HandlerThread implements Runnable {    
        private Socket socket;    
        public HandlerThread(Socket client) {   
       	 System.out.println("111111111111111");
            socket = client;    
            new Thread(this).start();    
        }    
 
        public void run() {    
            try {    
                // 读取客户端数据   
           	 System.out.println("222222222");
                BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));    
              	 System.out.println("333333333333");
                String clientInputStr = input.readLine();//这里要注意和客户端输出流的写方法对应,否则会抛 EOFException  
                // 处理客户端数据    
                System.out.println("客户端发过来的内容:" + clientInputStr);    

                // 向客户端回复信息    
                PrintStream out = new PrintStream(socket.getOutputStream());    
//                System.out.print("请输入:\t");    
//                // 发送键盘输入的一行    
//                String s = new BufferedReader(new InputStreamReader(System.in)).readLine();    
                out.println("OK");    
 
                out.close();    
                input.close();    
            } catch (Exception e) {    
                System.out.println("服务器 run 异常: " + e.getMessage());    
            } finally {    
                if (socket != null) {    
                    try {    
                        socket.close();    
                    } catch (Exception e) {    
                        socket = null;    
                        System.out.println("服务端 finally 异常:" + e.getMessage());    
                    }    
                }    
            }   
        }    
    }    

}

client:

package energy_use;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

public class Client {
    public static final int port = 3369;   
    public static final String host = "139.198.177.XX";
//    public static final String host = "127.0.0.1";


    
    public static void main(String[] args) throws Exception  {    
    	
    	while(true) {
    		Socket socket = new Socket(host,port);
//    		sock.connect(addr);
//    		SocketAddress addr = new InetSocketAddress(host,port);
//    		Socket socket = new Socket();
//    		socket.connect(addr);
    		//写数据
    		OutputStream os =socket.getOutputStream();
    		
//    		os.write("GET / HTTP/1.1\r\n".getBytes());
//    		os.write(("Host: " + "139.198.177.221\r\n").getBytes());
//    		os.write("Content-Type: application/x-www-form-urlencoded\r\n".getBytes());
//               //保持连接
//    		os.write("Connection: keep-alive\r\n".getBytes());
//    		os.write("Content-Length: 3\r\n".getBytes());
//    		os.write("\r\n".getBytes());
//    		
    		os.write("123\r\n".getBytes());

    		os.flush();
    		//shutdownOutput会关闭输出流,但是连接还是建立着的,相当于提示服务器我客户端输出完毕了。
    		//这样服务器才能在read方法里读出-1来,退出循环,不加shutdown服务器会在read方法处阻塞
//    		socket.shutdownOutput();
    		//读数据
    		InputStream is = socket.getInputStream();
    		byte[] readbuf = new byte[1024];
    		StringBuilder sb = new StringBuilder();
    		int len = is.read(readbuf);
    		while(len!=-1)
    		{
    			sb.append(new String(readbuf,0,len));
    			len = is.read(readbuf);
    		}
    		System.out.println("message from server:"+sb.toString());
    		Thread.sleep(5000);
    	}
		
}

这边客户端的请求末尾一定带上\r\n,表示发送完毕了。。不然服务器会一直等着,以为你没结束。。

我本地随便发的消息服务器都能收到,我以为我终于可以了,能拿到数据了,这烦人的东西终于结束了。。。结果,拿不到客户传的数据,白瞎。。。

我真的讨厌乱七八糟的一堆的群,真恶心。。。

补充:

因为客户消息是接收到就转发,而且第一次请求就卡在accept那里,所以合理怀疑是因为消息末尾没加\r\n导致的,其实如果他加上我应该就可以了,但是我决定先我自己解决。。。还好我比较幸运,网上有一种写法是异步接收消息,刚好能用。。

package com.cn.test;


import java.io.FileWriter;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;


public class Server {
	
	public static final int port = 8808;   
//    public static final String host = "139.198.XXX.XXX";
    public static void main(String[] args) {    
        System.out.println("Server...\n");    
        Server server = new Server();    
        server.init();    
    }    
    
    
    
    public void init() {    
        try {    
            //创建一个ServerSocket,这里可以指定连接请求的队列长度  
            ServerSocket server = new ServerSocket(port);    
            while (true) {    
                //从请求队列中取出一个连接
                Socket client = server.accept();    
                System.out.println("服务器接收到了请求");
                // 处理这次连接   
            	waitForData(client);
//                new HandlerThread(client);    
            }    
        } catch (Exception e) {    
            System.out.println("服务器异常: " + e.getMessage());    
            e.printStackTrace();
        }    
    }    
 
    private void waitForData(Socket client) {
        FutureTask<Void> futureTask = new FutureTask<>(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                try {
                    String charset = "GBK";
                    byte[] buffer = new byte[10240];
                    String msg;
                    int len;
                    InputStream inputStream = client.getInputStream();
//                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, charset));
                    while (true) {
                        if (!client.isInputShutdown()) {
                            len = inputStream.read(buffer);
                            if (len == -1) 
                            	break;
                            msg = new String(buffer, 0, len, charset);
                            System.out.println("========数据长度: " + msg.length());
                            saveData(msg+"\r\n");
//                            dealWithData(msg.trim());
                        }
                    }
                } catch (Exception e) {
                   e.printStackTrace();
                }
                return null;
            }
        });
        new Thread(futureTask).start();
    }
    
    private void saveData(String data) throws Exception{
    	if(data == null || "".equals(data.trim())) {
    		return;
    	}
    	String fileUrl = "C://Users/Administrator/Desktop/electric/";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH");
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String now = sdf.format(new Date());
        fileUrl = fileUrl + now + "_electric.txt";
        
        FileWriter fw = null;
        try {
            fw = new FileWriter(fileUrl, true);
            if(data.trim().matches("\\{.*\\}\\{.*\\}.*")) {
        		//{"ygdd":230322.671875,"deviceid":11140000000012,"timestamp":1670999240602}{"ygdd":230322.6796875,"deviceid":11140000000012,"timestamp":1670999244227}
        		data = data.trim().replace("}", "}\r\n").trim();	
        	}
            fw.write(data);
            fw.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            fw = null;
        }

       
    }
  
}

终于拿到了他们的数据。。。。mdzz,这周脏话已经严重超标了。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值