[tester::#PV1] error reading from connection: unexpected EOF

I’m stuck on Stage #PV1.

This is what I get from the tester as input

[tester::#PV1] Connecting to broker at: localhost:9092
[tester::#PV1] Connection to broker at localhost:9092 successful
[tester::#PV1] Sending "ApiVersions" (version: 4) request (Correlation id: 1112742846)
[tester::#PV1] Hexdump of sent "ApiVersions" request:
[tester::#PV1] Idx  | Hex                                             | ASCII
[tester::#PV1] -----+-------------------------------------------------+-----------------
[tester::#PV1] 0000 | 00 00 00 23 00 12 00 04 42 53 1b be 00 09 6b 61 | ...#....BS....ka
[tester::#PV1] 0010 | 66 6b 61 2d 63 6c 69 00 0a 6b 61 66 6b 61 2d 63 | fka-cli..kafka-c
[tester::#PV1] 0020 | 6c 69 04 30 2e 31 00                            | li.0.1.
[tester::#PV1]

and here is what I am responding with

[your_program] 0014 4253 1bbe 0000 0001 0012 0000 0004
[your_program] 0000 0000 0000

As far as I can tell this is correct, but the test is failing with

[tester::#PV1] error reading from connection: unexpected EOF
[tester::#PV1] Test failed
[tester::#PV1] Terminating program
[tester::#PV1] Program terminated successfully

Any suggestions on how to debug this?

1 Like

@raysuliteanu I tried running your code against the previous stages, but it’s no longer passing the second stage.

Suggestions:

  1. Use our CLI to test against previous stages by running:
codecrafters test --previous
  1. Focus on fixing the early stages first, as later stages depend on them.

i stuck into the same question:

[tester::#PV1] Running tests for Stage #PV1 (Handle APIVersions requests)
 [tester::#PV1] $ ./your_program.sh /tmp/server.properties
 [tester::#PV1] Connecting to broker at: localhost:9092
 [tester::#PV1] Connection to broker at localhost:9092 successful
 [tester::#PV1] Sending "ApiVersions" (version: 4) request (Correlation id: 1609643497)
 [tester::#PV1] Hexdump of sent "ApiVersions" request: 
 [tester::#PV1] Idx  | Hex                                             | ASCII
 [tester::#PV1] -----+-------------------------------------------------+-----------------
 [tester::#PV1] 0000 | 00 00 00 23 00 12 00 04 5f f1 35 e9 00 09 6b 61 | ...#...._.5...ka
 [tester::#PV1] 0010 | 66 6b 61 2d 63 6c 69 00 0a 6b 61 66 6b 61 2d 63 | fka-cli..kafka-c
 [tester::#PV1] 0020 | 6c 69 04 30 2e 31 00                            | li.0.1.
 [tester::#PV1] 
 [tester::#PV1] error reading from connection: unexpected EOF
 [tester::#PV1] Test failed
 [tester::#PV1] Terminating program
[tester::#PV1] Program terminated successfully

my codes follows below:

package main

import (
	"fmt"
	"net"
	"os"
	"io"
	"encoding/binary"
)

var _ = net.Listen
var _ = os.Exit

func main() {
	l, err := net.Listen("tcp", "0.0.0.0:9092")
	if err != nil {
		fmt.Println("Failed to bind to port 9092")
		os.Exit(1)
	}
	// defer l.Close()

	for {
		conn, err := l.Accept()
		if err != nil {
			fmt.Println("Error while accepting the connection: ", err.Error())
			os.Exit(1)
		}
		
		go handleConnection(conn)
	}

}

func handleConnection(conn net.Conn) {
	defer conn.Close()

	// read the request message
	request := make([]byte, 1024) 
	n, err := conn.Read(request) // n表示实际读取的字节数 n stands for the number of actually read bytes
	if err != nil {
		if err == io.EOF {
			fmt.Println("Reached EOF, connection closed by the server")
			return
		} 
		fmt.Println("读取请求时出错:", err.Error())
		return
	}
	if n < 4 {
		fmt.Println("请求消息大小不足")
		return
	}
	// fmt.Printf("十六进制格式: %x\n", request[8:12])

	// 准备响应 response
	messageSize := binary.BigEndian.Uint32( request[0:4] ) // request message size
	request_api_key := binary.BigEndian.Uint16( request[4:6] ) // api_version
	request_api_version := binary.BigEndian.Uint16( request[6:8] ) // max_version
	correlationID := binary.BigEndian.Uint32(request[8:12]) // extract correlation id
	
	// error codes
	error_code := 0
	if request_api_version != 0 && request_api_version != 1 && request_api_version != 2 && request_api_version != 3 && request_api_version != 4 {
		error_code = 35
	}

	// filling response slice
	response := make([]byte, 23) 

	binary.BigEndian.PutUint32(response[0:4], uint32(messageSize)) // 4 Byte
	binary.BigEndian.PutUint32(response[4:8], uint32(correlationID))
	binary.BigEndian.PutUint16(response[8:10], uint16(error_code)) 
	/*
	   Breakdown:
	       - First Byte: #apikeys +1 -> 2
	       - Next two bytes: API key; supposed to be 18 according to spec -> 0, 18
	       - Next two bytes: min version; supposed to be 0 -> 0, 0
	       - Next two bytes: max version; supposed to be 4 -> 0, 4
	       - Next byte: TAG_BUFFER -> 0
	       - Next four bytes: throttle_time_ms -> 0, 0, 0, 0
	       - Final byte: TAG_BUFFER -> 0
	*/
	response[10] = 2                              								// Number of API keys
	binary.BigEndian.PutUint16(response[11:13], uint16(request_api_key))  		// API Key 1 - API_VERSIONS
	binary.BigEndian.PutUint16(response[13:15], 0 )  							// min_version
	binary.BigEndian.PutUint16(response[15:17], uint16(request_api_version)) 	// max_version
	response[17] = 0  // tagged_fields
	binary.BigEndian.PutUint32(response[18:22], 0 ) // throttle_time_ms
	response[22] = 0	// TAG_BUFFER
	 

	// send the response to the cliend
	if _, err := conn.Write(response); err != nil {
		fmt.Println("Error while writing: ", err.Error())
	}
}

check your response where thee message size should be correct