问题
In order to read input 1 character at a time, I wrote a c program that uses ssty raw
.
I use this character.c
program to call an erlang file, naive_tcp.erl
which sends a message over socket to a listening server on the same machine.
I expect this server, naive_tcp2.erl
, to write back with 26 lines of descending integers and an 80 character long string with 2 "|" pipes in it, so that it lines up on the 80x26 terminal.
What happens instead is very inconsistent printing of data. Running ./character.c
, then pressing a key on the keyboard every few seconds, you can see the output starting with "26"
and descending down to "1"
, but instead you can see it descend to "23"
, "21"
or only "24"
.
character.c:
#include<stdio.h>
#include<stdlib.h>
int main(void){
system ("clear");
int c;
/* use system call to make terminal send all keystrokes directly to stdin */
system ("/bin/stty raw");
while((c=getchar())!= '.') {
char command[100];
sprintf(command, "erl -noshell -run naive_tcp go -s erlang halt");
system(command);
printf("\r\n");
/* type a period to break out of the loop, since CTRL-D won't work raw */
}
/* use system call to set terminal behaviour to more normal behaviour */
system ("/bin/stty cooked");
system ("clear");
system ("echo ok\n");
return 0;
}
naive_tcp.erl:
-module(naive_tcp).
-compile(export_all).
go() ->
Text = "hello",
{ok, Socket} = gen_tcp:connect({127,0,0,1}, 8094, []),
send(Socket, Text).
format() ->
format(26).
format(0) -> io:format("\r\n");
format(N) ->
io:format(integer_to_list(N)),
io:format(" | | "),
format(N - 1).
send(Socket, Msg) ->
inet:setopts(Socket, [{active, once}]),
gen_tcp:send(Socket, Msg),
receive
{tcp, Socket, <<"quit", _/binary>>} ->
gen_tcp:close(Socket);
{tcp, _, Res} ->
gen_tcp:close(Socket),
io:format(Res ++ "\r\n")
end.
naive_tcp2.erl
-module(naive_tcp2).
-compile(export_all).
go() ->
go(8094).
go(Port) ->
Pid = spawn_link(fun() ->
{ok, Listen} = gen_tcp:listen(Port, [binary, {active, false}]),
spawn(fun() -> acceptor(Listen) end),
timer:sleep(infinity)
end),
{ok, Pid}.
acceptor(ListenSocket) ->
{ok, Socket} = gen_tcp:accept(ListenSocket),
spawn(fun() -> acceptor(ListenSocket) end),
handle(Socket).
format(Socket) ->
format(26, Socket).
format(0, Socket) -> gen_tcp:send(Socket, "\r\n");
format(N, Socket) ->
gen_tcp:send(Socket, integer_to_list(N)),
gen_tcp:send(Socket, " | | "),
format(N - 1, Socket).
handle(Socket) ->
inet:setopts(Socket, [{active, once}]),
receive
{tcp, Socket, <<"quit", _/binary>>} ->
gen_tcp:close(Socket);
{tcp, Socket, Bin} ->
% gen_tcp:send(Socket, Bin)
% Msg = binary:bin_to_list(Bin),
format(Socket)
end,
handle(Socket).
running ./character
and hitting keys:
26 | | 25 | | 24 | | 23 | |
26 | | 25 | | 24 | | 23 | | 22 | | 21
26 | | 25 | | 24 | | 23 | |
26 | | 25 | | 24 | | 23 | | 22 | | 21 | | 20 | |
26 | | 25 | | 24 | | 23 | | 22 | | 21 | | 20
26 | | 25 | | 24
来源:https://stackoverflow.com/questions/42755951/inconsistent-tcp-socket-behavior-in-erlang