這是an earlier question的延續。我開始一個新線程,以便我可以顯示最新的完整服務器和客戶端代碼,包括我在該線程和Reddit上收到的所有建議。爲什麼我不能使用TCP客戶端發送兩條消息? (續)
我在Windows 7 Pro下運行。
我有一個用Python編寫的非常簡單的TCP服務器。它創建一個socketserver對象並等待消息。當到達時,服務器將其打印到其控制檯並通過相同的端口發回簡單的確認。
客戶端向服務器發送編號消息,等待確認並顯示它。然後它會詢問用戶是否應該發送另一條消息。
第一封郵件已成功發送並確認。在客戶端,看起來第二條消息發送成功;對網絡流的Write()方法的調用成功。但是,當調用Read()消息來獲取確認時,會拋出異常:「建立的連接被主機中的軟件中止。」
這裏是服務器代碼:
import json
import threading
import socketserver
import time
with open('CAPS_TWMS_config.json', 'rt') as c:
caps_config = json.load(c)
# We are listening on this port and all defined IP addresses
# listenPort = 5001
listenPort = caps_config["listen_port"]
# Were to send the information to.
clientIPAddress = '127.0.0.1' # socket.gethostbyname('client')
# clientPort = 12345
clientPort = caps_config["send_port"]
dsnName = caps_config["dsn_name"]
# Message sequence number
sequence_num = 1
exit_app = False
class ListenSocketHandler(socketserver.BaseRequestHandler):
"""
The RequestHandler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def __init__(self, request, client_address, this_server):
socketserver.BaseRequestHandler.__init__(self, request, client_address, this_server)
self.timeout = 10
def handle(self):
try:
data = self.request.recv(1024).decode()
# print (str.format("dataString[21]: {0}; dataString[24:26]: {1}", data[21], data[24:26]))
print ('ListenSocketHandler recv()-> "%s"' % data)
print ('ListenSocketHandler recv().length-> "%d"' % len(data))
if len(data) > 0:
self.request.send("I got a message!".encode())
return
except Exception as value:
print('ListenSocketHandler - %s' % str(value))
return
class ListenServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
"""
The multi-threaded server that will spawn threads running the Socket Handler for each
connection
"""
pass
if __name__ == '__main__':
try:
# Create the Server Handler for connections to this computer listening on all IP addresses,
# change '' to 'x.x.x.x' to listen on a specific IP network. This class will listen for messages # from CAPS.
server = ListenServer(('', listenPort), ListenSocketHandler)
ip, port = server.server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.setDaemon(True)
server_thread.start()
while not exit_app:
time.sleep(1)
print ('Out of main loop.')
server.shutdown()
server.server_close()
except Exception as value:
print("Failed to do something: %s", str(value))
下面是客戶端代碼:
private void button1_Click(object sender, EventArgs e)
{
TcpClient client = new TcpClient();
try
{
client.Connect("127.0.0.1", 5001);
NetworkStream stream = client.GetStream();
int messageCount = 1;
while (true)
{
// Translate the passed message into ASCII and store it as a Byte array.
string message = string.Format("This is message {0}", messageCount++);
Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
// Receive the TcpServer.response.
// Buffer to store the response bytes.
data = new Byte[1024];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 receivedCount = 0;
int sleepCount = 0;
while (receivedCount == 0)
{
receivedCount = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, receivedCount);
if (receivedCount == 0)
{
Thread.Sleep(250);
if (sleepCount++ > 20)
{
MessageBox.Show("Response timeout.");
break;
}
}
}
if (MessageBox.Show("Reply: " + responseData + " Try again?", "Try again?", MessageBoxButtons.YesNo) == DialogResult.No)
{
break;
}
}
client.Close();
}
catch (Exception ex)
{
MessageBox.Show("Failed to do something with TcpClient: " + ex.Message);
}
}
您如何期待服務器知道一個請求的結束和下一個請求的開始? –
此外,在從處理程序返回之前,請嘗試'self.request.shutdown(socket.SHUT_RDWR)' –
檢查以查看是否要訪問:client.Close();. TCP在消息中使用零字節獲取數據是正常的,因此接收計數可能爲零,您將退出while循環。您需要接收,直到收到所有數據。因此,使用3種方法中的1種:1)Ascii:接收,直到接收到已知字符,如'\ n'2)Ascii或Binary:將字節數添加到消息開頭,並讀取直到接收到所有字節。 3)ASCII或二進制:固定長度的消息。每個消息(或消息類型)具有已知數量的字符。 – jdweng