进一步探究linux下erlang关闭port同时也关掉与其连接的c语言进程

经过上篇文章“linux下erlang关闭port同时也关掉与其连接的c语言进程”的分析,我们澄清了erlang关闭端口时,stdin会得到一个feof,进而关闭stdin。经过进一步的探究,发现有另两种新的解决方法:

第一:借助于linux下read函数,read函数原型:

          ssize_t read(int fd,void *buf,size_t count)
函数返回值分为下面几种情况:

1、如果读取成功,则返回实际读到的字节数。这里又有两种情况:一是如果在读完count要求字节之前已经到达文件的末尾,那么实际返回的字节数将小于count值,但是仍然大于0;二是在读完count要求字节之前,仍然没有到达文件的末尾,这是实际返回的字节数等于要求的count值。

2、如果读取时已经到达文件的末尾,则返回0。

3、如果出错,则返回-1。

因此,当erlang关闭端口时,read(0,buf,len)会返回0,此该让c进程退出。具体做法是

#include <stdio.h>
#include <unistd.h>
typedef unsigned char byte;
typedef char int8;
int main() {
    FILE * fp;
    fp = fopen("ports.log", "a+");
    fprintf(fp, "start...\n");
    fflush(fp);
    byte buf[256]={0};
 int i = 0;
    for(;;)
 {
    int8 len = buf[0];
   
  
  //方法1:利用feof时,read返回0
    if ((i=read(0, buf, 3)) <= 0)
    return (i);

     write(1, buf, 3);
 }

附:erlang的port_close()关闭时,read返回0并不是erlang进程向c进程发了0字节的东西,因为经过实验是无法向stdin中写0字节的东西, Port ! {self(), {command, “”}}c进程并没有挂掉,推导出read并没有返回0。

第二、借助于struct _IO_FILE结构体中的_flags字段,该字段的含义_flags:true表示stdin关闭;_flags:false表示stdin打开;

It's in /usr/include/libio.h (which is included in stdio.h) and struct defintion is:

struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ #define _IO_file_flags _flags /* The following pointers correspond to the C++ streambuf protocol. */ /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */  char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ char* _IO_write_end; /* End of put area. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */ /* The following fields are used to support backing up and undo. */  char *_IO_save_base; /* Pointer to start of non-current get area. */ char *_IO_backup_base; /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */ struct _IO_marker *_markers; struct _IO_FILE *_chain; int _fileno; #if 0  int _blksize; #else  int _flags2; #endif  _IO_off_t _old_offset; /* This used to be _offset but it's too small. */ #define __HAVE_COLUMN /* temporary */ /* 1+column number of pbase(); 0 is unknown. */  unsigned short _cur_column; signed char _vtable_offset; char _shortbuf[1]; /* char* _save_gptr; char* _save_egptr; */  _IO_lock_t *_lock; #ifdef _IO_USE_OLD_IO_FILE };

具体方法是:

#include <stdio.h>
#include <unistd.h>
typedef unsigned char byte;
typedef char int8;
int8 read_exact(byte* buf, int8 len);
int8 write_exact(byte* buf, int8 len);
int main() {
    FILE * fp;
    fp = fopen("ports.log", "a+");
    fprintf(fp, "start...\n");
    fflush(fp);
    byte buf[256]={0};
 int i = 0;
    for(;;)
 {
    int8 len = buf[0];
         //方法2:利用feof时,置标志位_flags:true表示stdin关闭;_flags:false表示stdin打开;
     read(0, buf, 3);

 if(stdin->_flags)
  {
        fprintf(fp, "stdin closed by erlang\n");
         return (i);
  }
          write(1, buf, 3);
 }

为了验证性能:此时if(stdin->_flags)并不是一直在不停的判断,只是在port_close关闭stdin,对其置位时执行。此结论是通过反推得出的,具体实验如下:

将判断改为其反面,即stdin不关闭时写文件if(!stdin->_flags) fprintf(fp, "stdin closed by erlang\n");替换掉上面的if(stdin->_flags){fprintf(fp, "stdin closed by erlang\n");
     return (i);}部分,结果发现在端口打开正常工作时,并没有发生写文件的动作;当改成if(stdin->_flags) fprintf(fp, "stdin closed by erlang\n");即置位后不退出,这样
当erlang关闭端口时_flags置位了,由c进程没有退出,此条件成立,故发生了循环写文件动作。结论:c进程对stdin的动作判断与erlang进程紧密相关,并不是单方面的情况,具体的执行时隙问题,留待以后进一步分析。

附:erl的测试程序如下:

-module(echo).
-export([start/0, stop/0, echo/1]).

start() ->
    spawn(fun() ->
            register(echo, self()),
            process_flag(trap_exit, true),
            Port = open_port({spawn, "./echo"}, []),

            loop(Port)
        end).

stop() ->
    echo ! stop.

echo(Msg) ->
    echo ! {call, self(), Msg},    %% Msg必须是一个List
    receive
        Result -> Result
    after 1000 -> io:format("time out~n"), true
    end.

loop(Port) ->
    receive
        {call, Caller, Msg} ->
            Port ! {self(), {command, Msg}},    %% Msg必须是一个List
            receive
                {Port, {data, Data}} ->     %% 返回的Data也是一个List
                    Caller ! Data
            end,
            loop(Port);
        stop ->
            Port ! {self(), close},
            receive
                {Port, closed} -> exit(normal)
            end;
        {'EXIT', Port, Reason} ->
            io:format("~p terminated !~n",[Port]),
            exit({port_terminated, Reason})
end.

 

你可能感兴趣的:(进一步探究linux下erlang关闭port同时也关掉与其连接的c语言进程)