2014-10-29 54 views
0

所以,在使用Java和Python編程套接字時,我偶然發現了一些奇怪的東西。接收端的套接字在打印時分割數據

使用Java將消息發送到Python套接字的接收端時,它會將消息拆分爲兩部分,即使這並非意圖。

我可能犯了一個錯誤,導致這個問題,但我真的不知道它是什麼。

你可以看到,Java的發送 「測試1」 中的一個命令和Python只收到部分消息:

http://i.imgur.com/tbwa7C5.png

Pyhton服務器套接字來源:

''' 
Created on 23 okt. 2014 

@author: Rano 
''' 

#import serial 
import socket 

HOST = '' 
PORT = 1234 
running = True; 

skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
skt.bind((HOST, PORT)) 
skt.listen(1) 
conne, addr = skt.accept() 

#ser = serial.Serial('/dev/tty.usbmodem411', 9600) 

while running == True: 
    data = conne.recvall(1024) 

    if(data == "quit"): 
     running = False 
     break 

    rawrecvstring = data + "" 
    recvstring = rawrecvstring.split("|") 
    print(recvstring[0]) 

#_______________________ABOVE IS RECEIVE_______________UNDER IS SEND_______________________#  

# sendstring = ser.readline() 
# if sendstring != "": 
#  conne.sendall(sendstring) 


conne.close() 
#ser.close() 

和Java的Socket發送功能:

private String message; 
private DataOutputStream out; 
private BufferedReader in; 
private Socket socket; 
private boolean socketOnline; 

public SocketModule(String IP, int Port){ 
    try { 
     socket = new Socket(IP, Port); 
     out = new DataOutputStream(socket.getOutputStream()); 
     in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
    } catch (UnknownHostException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
}; 

void setMessage(String s){ 
    try { 
     out.writeBytes(s); 
     out.flush(); 
     System.out.println("message '" + s + "' sent!\n"); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
}; 

任何想法爲什麼消息被拆分?

+0

的Java發送「Test1Test1Test1」之間衝廁。 'awrecvstring.split(「|」)'不知何故尋找一個'|'字符?沒有發送這樣的字符。也看看http://stackoverflow.com/a/20352105/995891'DataOutputStream#writeBytes(String)'很少是一個好主意 – zapl 2014-10-29 22:46:55

+0

@zapl我打算髮送一個字符串「|」我需要知道的值之間的字符。這樣我就可以分割字符串並將所有的值都存入recvstring數組中。 – 2014-10-29 22:50:15

回答

1

TCP是一個流協議,而不是消息協議。

就TCP而言,s.send("abd"); s.send("def");s.send("abcdef")完全一樣。在套接字的另一端,當您接收郵件時,它可能會在第一次發送到達時立即返回,並給您​​,但它可以簡單地返回"abcdef""a""abcd"。他們都完全合法,你的代碼必須能夠處理所有這些。

如果你想分開處理整個消息,建立一個描述消息的協議,這是否意味着使用一些不能出現在實際數據中的分隔符(可能是因爲,如果它出現在實際的數據,你逃避它),或者每個消息的長度前綴,或者使用一些自我描述的格式,如JSON。

它看起來像你是建立這樣一個事情的一部分,因爲你有一些原因split('|')。但是你仍然需要添加剩下的部分 - 循環接收字節,將它們添加到緩衝區,將所有完整的消息從緩衝區中分離出來處理它們,並在最後爲下一個循環保留任何不完整的消息。當然,在另一邊發送|分隔符。

例如,你的Java代碼可以做到這一點:

out.writeBytes(s + "|"); 

然後,在Python的一面:

buf = "" 
while True: 
    data = conne.recvall(1024) 
    if not data: 
     # socket closed 
     if buf: 
      # but we still had a leftover message 
      process_message(buf) 
     break 
    buf += data 
    pieces = buf.split("|") 
    buf = pieces.pop() 
    for piece in pieces: 
     process_message(piece) 

process_message功能可以處理特殊的 「跳槽」 的消息,打印出任何東西別的,無論你想要什麼。 (如果它足夠簡單,你可以將它內聯到它被稱爲的兩個地方。)

從一條評論,它聽起來像你想要使用該|來分隔每個消息內的字段,而不是單獨的消息。如果是這樣,只需選擇另一個永遠不會出現在您的數據中的字符,並使用該字符代替上面的|(然後在process_message內執行msg.split('|'))。一個非常好的選擇是\n,因爲那麼(在Python端)可以使用socket.makefile,它爲您提供了一個類似文件的對象,爲您執行緩衝操作,並且在迭代它時只是逐一產生行(或者調用readline它,如果你喜歡)。請參閱Sockets are byte streams, not message streams

作爲一個附註,我也刪除了running的標誌,因爲只有一次你要設置它,你也會去break,所以它沒有任何好處。 (但如果你要測試標誌,只是用while running:,不while running == True:。)

+0

感謝您的信息和舉例!我打算髮送1個字符串中的多個值與「|」字符介於它們之間來分離這些值並將它們放入recvstring數組中。我現在要去睡覺,但明天我會試一試。再次感謝您的時間,感謝它! – 2014-10-29 22:56:23

+0

我只是試過你的代碼,它在我的本地網絡上完美地工作。謝謝! – 2014-10-30 12:03:01

+0

@RanoV:太好了!那麼,您是否理解使用「兩級分隔線」分隔記錄並分隔記錄中的字段的部分? (如果沒有,可能會幫助您考慮CSV文件:行之間的換行符,列之間的逗號) – abarnert 2014-10-30 18:24:48