Tcp hang on read

Help me I’m a :clown_face:

I’ve been working on this little server for my job.
Long and short of it is that it is a completion engine for some command line functions.

SO,

There is a tcp server I wrote out there chilin and the shell completion will interface with said server via tcp as a client.

BUT,

I can’t get the tcp read to work. I’ve no clue why.
I’ve tried various functions. read readall readbyte readdelimiter etc.
nada.

Just using an echo | nc works though.

Here is the stack where it just hangs on the read call. Looks like I make it all the way to a syscall so it is probably just me not fully understanding tcp or something.

image
Sorry for trim. I don’t want to leak company info.

I have client → write → server read → server write → hang on client read.

Associated server code

while (true) {
         print("Listening on {}\n", .{addr.getPort()});
         var client = try server.accept();
         print("Connection received! {} is sending data.\n", .{client.address});
         const message = try client.stream.reader().readAllAlloc(gpa_allocator, 1024);
         print("Recieved data.\n", .{});
         defer gpa_allocator.free(message);
         if (uris.search_uris(message)) {
             print("found {s}\n", .{message});
             print("about to write: \n", .{});
             _ = try client.stream.writer().writeAll("hello\t");
             client.stream.close();
             print("post write: \n", .{});
         } else {
             print("failed to locate {s}.", .{message});
             _ = try client.stream.writer().writeAll("no-op\t");
             client.stream.close();
            // uris.print();
         }
     }

Associated client code

    // Connect to peer
    const stream = try std.net.tcpConnectToAddress(peer);
    defer stream.close();

    // Sending data to peer
    const data = "/features";
    var writer = stream.writer();
    _ = try writer.writeAll(data);
    std.debug.print("post write", .{});

    var resp_buffer: [1000]u8 = undefined;
    // std.debug.print("about to read", .{});
    // _ = try reader.readUntilDelimiter(&resp_buffer, '\t');
    var reader = stream.reader();
    const byte = try reader.read(&resp_buffer);
    std.debug.print("byte: {}", .{byte});
    // END OF MAIN

Apologies for weird naming. It’s the remains of me struggling to get it to work. It has to be something simple and small. :clown_face: <me

This may have changed (haven’t tried it) but I remember reading somewhere that this type of chaining for reader and writer doesn’t work. You have to obtain the reader first and then use it:

const reader = client.stream.reader();
try reader.readAll(...);

Are you sure that is what is happening?

I think this line is where you are hanging since it will wait until the connection closes or the client has sent 1024 bytes of data.

I mean I’m fairly confident that I’m right that I hang on the read. If I remove the read my server finishes the write.

I tried your recommended code same behavior.

I’m gonna try updating zig and see if anything changes.

Just to clarify: I copy pasted your code and ran it locally, and the server hangs on the readAllAlloc call. The client then also hangs on the read because it is blocking waiting for a server write that never comes.

Simplifying the server to the following with a simple read call into a stack buffer runs correctly.

// server.zig
const std = @import("std");

pub fn main() !void {
    const addr = try std.net.Address.parseIp("0.0.0.0", 8080);
    var server = try addr.listen(.{});
    std.debug.print("Listening on {}\n", .{addr.getPort()});
    
    while (true) {
         var client = try server.accept();
         std.debug.print("Connection from {}\n", .{client.address});

         var buffer: [1024]u8 = undefined;
         const len = try client.stream.reader().read(&buffer);
         std.debug.print("Recieved: {s}\n", .{buffer[0..len]});

         _ = try client.stream.writer().writeAll("no-op\t");
         client.stream.close();
     }
}
// client.zig
const std = @import("std");

pub fn main() !void {
    const addr = try std.net.Address.parseIp("127.0.0.1", 8080);
    const stream = try std.net.tcpConnectToAddress(addr);
    defer stream.close();

    const data = "/features";
    var writer = stream.writer();
    _ = try writer.writeAll(data);
    std.debug.print("Sent: {s}\n", .{data});

    var resp_buffer: [1000]u8 = undefined;
    var reader = stream.reader();
    const len = try reader.read(&resp_buffer);
    std.debug.print("Received: {s}\n", .{resp_buffer[0..len]});
}
1 Like

I know this is very simple, but I just couldn’t get it to work.
lma…Ohno :clown_face:

I was in the process of putting std.debug.print in the actual library…

You’ve saved me some time. Thanks.