我想编写一个程序来模拟串行端口上的设备。我正在尝试使用伪终端来完成此操作。我想要一个独特的过程来控制主人。此过程充当串行设备仿真器。我希望另一个进程(例如 kermit)能够使用从终端与主进程通信。由于不同的工艺要求,我没有使用任何 fork 。互联网上几乎每个伪终端示例都显示了 fork() 用于主/从。
我让它朝一个方向工作。也就是说,我可以让从进程将数据写入从伪终端,而主进程将从主伪终端读取它就好了。
问题在另一个方向。无法让master写数据,slave读数据。
我将展示无效的双向代码和有效的单向代码。
非工作双向主机:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
// get the master fd
int masterfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
if(masterfd < 0)
{
perror("getpt");
exit(1);
}
// grant access to the slave
if(grantpt(masterfd) < 0)
{
perror("grantpt");
exit(1);
}
// unlock the slave
if(unlockpt(masterfd) < 0)
{
perror("unlockpt");
exit(1);
}
// get the path to the slave
char slavepath[64];
if(ptsname_r(masterfd, slavepath, sizeof(slavepath)) < 0)
{
perror("ptsname_r");
exit(1);
}
printf("Using %s\n", slavepath);
char bufout = 'D';
char bufin;
int c;
while(1)
{
printf("reading\n");
c = read(masterfd, &bufin, 1);
printf("read %i bytes: %c\n", c, bufin);
if(c == -1) break;
if(bufout == 'D') bufout = 'E';
else if(bufout == 'E') bufout = 'D';
printf("writing %c\n", bufout);
c = write(masterfd, &bufout, 1);
printf("wrote %i bytes\n", c);
if(c == -1) break;
sleep(1);
}
close(masterfd);
return 0;
}
非工作双向从站:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/pts/15", O_RDWR | O_NOCTTY);
if(fd < 0)
{
perror("open");
exit(1);
}
char bufout = 'A';
char bufin;
int c;
while(1)
{
if(bufout == 'A') bufout = 'B';
else if(bufout == 'B') bufout = 'A';
printf("writing %c\n", bufout);
c = write(fd, &bufout, 1);
if(c == -1) break;
printf("reading\n");
c = read(fd, &bufin, 1);
printf("read %i bytes: %c\n", c, bufin);
if(c == -1) break;
sleep(1);
}
close(fd);
}
非工作主机的输出: (注意接收到的第一个字符来自 slave,然后其余的字符由 master 写入。换句话说,master 正在读出它写给 master pts 的相同字符并且它忽略了 slave 正在写的内容,除了第一个字符。)
Using /dev/pts/15
reading
read 1 bytes: B [<--- FROM THE SLAVE]
writing E
wrote 1 bytes
reading
read 1 bytes: E [<--- REST FROM THE MASTER]
writing D
wrote 1 bytes
reading
read 1 bytes: D
writing E
wrote 1 bytes
reading
read 1 bytes: E
writing D
wrote 1 bytes
reading
read 1 bytes: D
^C
非工作奴隶的输出:(永远不会收到主人正在写的东西。)
writing B
reading
^C
工作单向大师:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
// get the master fd
int masterfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
if(masterfd < 0)
{
perror("getpt");
exit(1);
}
// grant access to the slave
if(grantpt(masterfd) < 0)
{
perror("grantpt");
exit(1);
}
// unlock the slave
if(unlockpt(masterfd) < 0)
{
perror("unlockpt");
exit(1);
}
// get the path to the slave
char slavepath[64];
if(ptsname_r(masterfd, slavepath, sizeof(slavepath)) < 0)
{
perror("ptsname_r");
exit(1);
}
printf("Using %s\n", slavepath);
char bufout = 'D';
char bufin;
int c;
while(1)
{
printf("reading\n");
c = read(masterfd, &bufin, 1);
printf("read %i bytes: %c\n", c, bufin);
if(c == -1) break;
sleep(1);
}
close(masterfd);
return 0;
}
工作单向奴隶:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/pts/15", O_RDWR | O_NOCTTY);
if(fd < 0)
{
perror("open");
exit(1);
}
char bufout = 'A';
char bufin;
int c;
while(1)
{
if(bufout == 'A') bufout = 'B';
else if(bufout == 'B') bufout = 'A';
printf("writing %c\n", bufout);
c = write(fd, &bufout, 1);
if(c == -1) break;
sleep(1);
}
close(fd);
}
工作主机的输出:(读取从机成功写入的内容。)
Using /dev/pts/15
reading
read 1 bytes: B
reading
read 1 bytes: A
reading
read 1 bytes: B
reading
read 1 bytes: A
reading
read 1 bytes: B
^C
工作奴隶的输出:
writing B
writing A
writing B
writing A
writing B
^C
最佳答案
我注意到如果我们使用像 screen 或 picocom 这样的终端仿真器而不是您的从属程序,您的第一个示例就可以工作。
我认为不同之处在于不同的线路“ cooking ”设置。这是 pts 创建时的默认状态:
$ stty -F /dev/pts/2
speed 38400 baud; line = 0;
-brkint -imaxbel
现在,在使用 screen 打开后,它变成了:
$ stty -F /dev/pts/2
speed 9600 baud; line = 0;
kill = ^H; min = 100; time = 2;
-icrnl -imaxbel
-opost -onlcr
-isig -icanon -echo
然后我尝试在读/写操作之前在从程序中将 pts 设置为原始模式。原始模式是线路设置的组合,可以尽可能多地禁用 cooking 。
struct termios ts;
if(tcgetattr(fd, &ts))
{
perror("tcgetattr");
exit(1);
}
cfmakeraw(&ts);
tcsetattr (fd, TCSANOW, &ts);
看起来它可以正常工作。
大师:
$ ./pts_master
Using /dev/pts/2
reading
read 1 bytes: B
writing E
wrote 1 bytes
reading
read 1 bytes: A
writing D
wrote 1 bytes
reading
read 1 bytes: B
writing E
wrote 1 bytes
...
奴隶:
$ ./pts_slave
writing B
reading
read 1 bytes: E
writing A
reading
read 1 bytes: D
writing B
...
关于c - 如何使用单独的进程但不 fork 地读取/写入 Linux 伪终端?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23459520/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t