Jestem nowy w Scali, więc pytanie może być dość proste, chociaż poświęciłem trochę czasu na rozwiązanie problemu. Mam prosty serwer Scala TCP (nie aktorów, single thread):Problemy z gniazdami w prostym serwerze Scala TCP
import java.io._
import java.net._
object Application {
def readSocket(socket: Socket): String = {
val bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream))
var request = ""
var line = ""
do {
line = bufferedReader.readLine()
if (line == null) {
println("Stream terminated")
return request
}
request += line + "\n"
} while (line != "")
request
}
def writeSocket(socket: Socket, string: String) {
val out: PrintWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream))
out.println(string)
out.flush()
}
def main(args: Array[String]) {
val port = 8000
val serverSocket = new ServerSocket(port)
while (true) {
val socket = serverSocket.accept()
readSocket(socket)
writeSocket(socket, "HTTP/1.1 200 OK\r\n\r\nOK")
socket.close()
}
}
}
Serwer nasłuchuje na localhost:8000
żądań przychodzących i wysyła odpowiedź HTTP z pojedynczego OK
słowo w organizmie. Następnie uruchamiam Apache Benchmark w ten sposób:
ab -c 1000 -n 10000 http://localhost:8000/
który działa ładnie po raz pierwszy. Za drugim razem zacznę ab
zawiesza produkcję następujący wynik w netstat -a | grep 8000
:
....
tcp 0 0 localhost.localdo:43709 localhost.localdom:8000 FIN_WAIT2
tcp 0 0 localhost.localdo:43711 localhost.localdom:8000 FIN_WAIT2
tcp 0 0 localhost.localdo:43717 localhost.localdom:8000 FIN_WAIT2
tcp 0 0 localhost.localdo:43777 localhost.localdom:8000 FIN_WAIT2
tcp 0 0 localhost.localdo:43722 localhost.localdom:8000 FIN_WAIT2
tcp 0 0 localhost.localdo:43725 localhost.localdom:8000 FIN_WAIT2
tcp6 0 0 [::]:8000 [::]:* LISTEN
tcp6 83 0 localhost.localdom:8000 localhost.localdo:43724 CLOSE_WAIT
tcp6 83 0 localhost.localdom:8000 localhost.localdo:43786 CLOSE_WAIT
tcp6 1 0 localhost.localdom:8000 localhost.localdo:43679 CLOSE_WAIT
tcp6 83 0 localhost.localdom:8000 localhost.localdo:43735 CLOSE_WAIT
tcp6 83 0 localhost.localdom:8000 localhost.localdo:43757 CLOSE_WAIT
tcp6 83 0 localhost.localdom:8000 localhost.localdo:43754 CLOSE_WAIT
tcp6 83 0 localhost.localdom:8000 localhost.localdo:43723 CLOSE_WAIT
....
Ponieważ że nie więcej żądań są obsługiwane przez serwer. Jeszcze jeden szczegół: ten sam skrypt ab
z tymi samymi parametrami działa sprawnie testując prosty serwer Node.js na tym samym komputerze. Więc ten problem nie jest związany z liczbą otwartych połączeń TCP, który postawiłem jako wielokrotnego użytku z
sudo sysctl -w net.ipv4.tcp_tw_recycle=1
sudo sysctl -w net.ipv4.tcp_tw_reuse=1
Czy ktoś może mi dać wskazówkę na temat tego, co mi brakuje?
Edit: Zakończenie postępowania strumień został dodany do powyższego kodu:
if (line == null) {
println("Stream terminated")
return request
}
CLOSE_WAIT oznacza, że TCP czeka dla tej aplikacji, aby zamknąć swoje gniazdo. Innym problemem jest to, że nie wysyłasz poprawnych terminatorów linii dla HTTP. Są one określone jako \ r \ n, a nie \ n. – EJP
Zaktualizowałem kod do '\ r \ n' chociaż' curl' i 'ab' oba wydają się działać dobrze z' \ n'. Co do CLOSE_WAIT - to nie wydaje się być źródłem problemu. Dziękuję za komentowanie. – nab
CLOSE_WAIT jest symptomem problemu, że aplikacja nie zamknęła gniazda. – EJP