【问题标题】:Socket Python(Server) to Java(Client) connection Java is not able to receive data from host套接字 Python(服务器)到 Java(客户端)连接 Java 无法从主机接收数据
【发布时间】:2018-04-29 17:06:19
【问题描述】:

Server 接收到来自 Client 的 String 请求,并回复一个 String 消息给 Client。

我认为服务器必须以不同于现在的方式发送回复,所以我认为应该更改此行:c.sendall('Server: '+str.encode(reply))

Python 服务器:

# This Python file uses the following encoding: utf-8
import socket

def setupServer(port):
    serv=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print("socket ist da")
    try:
        # https://stackoverflow.com/questions/166506/finding-local-ip-addresses-using-pythons-stdlib
        host=socket.gethostbyname(socket.gethostname())
        print('Host ip: '+host)
        serv.bind((host, port))
    except socket.error as msg:
        print(msg)
    print("socket bind fertig")
    return serv

def setupConnection(s):
    # Erlaubt 1 Verbindung gleichzeitig
    s.listen(1)
    connection, address=s.accept()
    print("Verbunden zu: "+address[0]+":"+str(address[1]))
    return connection


def gET():
    reply='GET ausgefuehrt'
    return reply

def rEPEAT(te):
    reply=te[1]
    return reply

def dataTransfer(c,s):
    # sendet und erhält Daten bis es stoppen soll
    while True:
        # Daten erhalten
        data=c.recv(1024)#daten erhalten 1024 Buffer size
        data=data.decode('utf-8')#nötig?
        # Teilt die Datei in Befehl/Command und data auf
        dataMessage=data.split(' ',1)
        command=dataMessage[0]
        if command=='GET'or command=='get':
            reply=str(gET())
        elif command=='REPEAT'or command=='repeat':
            reply=str(rEPEAT(dataMessage))
        elif command=='EXIT'or command=='exit':
            print("Er ist geganngen")
            break
        elif command=='KILL'or command=='kill':
            print("Server wird geschlossen!")
            s.close()
            break
        else:
            print("was?")
            reply="Nicht Vorhandener Befehl"
        # NAchricht senden
        c.sendall('Server: '+str.encode(reply))
        print(reply)
        print('Klint: '+data)
        print("Daten wurden geschickt")
    c.close()

def main():
    #print("hello")
    #host='192.168.1.120'
    #host='192.168.2.110'
    #print('Host ip: '+str(host))
    port=8999
    print('Port: '+str(port))
    s=setupServer(port)


    while True:
        try:
            conn=setupConnection(s)
            dataTransfer(conn,s)
        except:
            break

if __name__=="__main__":
    main()

Java 客户端线程:

public class SentThread extends Thread {

    Socket socket;
    Context cmain;
    //boolean stop=false;
    SentThread(Socket s,Context c) {
        socket = s;
        cmain=c;
    }

    @Override
    public void run() {
        Log.i("Roman", "run->");

        socket=new Socket();
        try{
        socket.connect(new InetSocketAddress("192.168.2.110", 8999),5000);
        }catch (Exception e) {
            Log.e("Roman", e.toString());
            Toast.makeText(cmain, e.toString(), Toast.LENGTH_SHORT).show();

        }


        try {
            BufferedReader stdIn = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            while (true) {
                out.print("Try");
                out.flush();
                System.out.println("Message sent");
                System.out.println("Trying to read...");
                String in = stdIn.readLine();
                System.out.println(in);
            }
        } catch (Exception e) {
            // TODO: handle exception
            Log.e("Roman", e.toString());
        }
    }
}

程序卡在String in = stdIn.readLine();

我不知道 java 应用程序能够从服务器接收消息的方式,即使 Java 程序能够向服务器发送消息。

提前谢谢你

【问题讨论】:

  • 您混淆了发送/接收协议。当您从 Java 发送时,您打印没有任何终止符的字符串,并“刷新”输出流。在 python 端,c.recv() 将返回一条不超过 1024 字节的任意大小的消息。无法保证您会收到完整的消息。您可能获得的字节数少于发送的字节数,并且必须再次调用 recv 以获取剩余的字节数,或者如果消息是背靠背发送的,您可能会从下一条消息中获得额外的字节数。另一方面,您没有冲洗,也没有发送换行符; readLine() 正在等待您从未发送过的字符
  • 修正了一些格式和语法。

标签: java python sockets readline transfer


【解决方案1】:

如果您想使用“面向行”的协议与服务器通信(即,发送的每一行都以\n 终止,使用readline 类型函数读取行,您应该为套接字创建file 对象在 python 中,只需在输入/输出语句中使用这些 sock_insock_out 对象而不是标准 IO 通道 sys.stdinsys.stdout

socket.makefile() 用于创建sock_insock_out 文件对象。使用encoding='utf-8'指定Python字符与socket的字节流之间的转换。

c.sendall 根本没有使用。相反,我们使用print(..., file=sock_out) 来传输文本。 flush=True 只能用于响应任何单个命令的服务器的最后输出;它可以用于每个输出语句,但会导致更多开销和更低的性能。

这是一个最小的、完整的、可验证的示例,例如 Python3.6 中的服务器。除了exitkill 命令之外,它只是回显发送给它的任何内容。您可以使用 telnet localhost 8889 之类的命令在不涉及 Java 客户端的情况下对其进行测试。

server.py:

import socket

class ClientKill(Exception):
    pass


def _serviceClient(sock_in, sock_out):
    for line in sock_in:
        line = line.rstrip('\n')

        if line == 'exit':
            break
        if line == 'kill':
            raise ClientKill()

        print(line, file=sock_out, flush=True) # Echo back


def serviceClient(client, addr):
    with client, client.makefile('r', encoding='utf-8', newline='\n') as sock_in, \
                 client.makefile('w', encoding='utf-8', newline='\n') as sock_out:
        _serviceClient(sock_in, sock_out)


port = 8889
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as listener:
   listener.bind(('localhost', port))
   listener.listen(0)

   try:
       while True:
           client, addr = listener.accept()
           serviceClient(client, addr)

   except ClientKill:
       print("Server killed by remote client")

在 Java 方面,改变 ...

 out.print("Try");
 out.flush();

...到...

 out.println("Try");
 out.flush();

... 否则服务器将继续等待终止从客户端发送的行的\n 字符。

另外,由于我们在 python 服务器上明确使用utf-8 作为编码,您应该在InputStreamReader 中添加相应的字符编码,并将socket.getOutputStream() 包装在具有相同编码的OutputStreamWriter 中。

【讨论】:

    猜你喜欢
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 2022-01-21
    • 1970-01-01
    • 2023-01-03
    • 1970-01-01
    相关资源
    最近更新 更多