我正在编写一个程序,使用 php 中的 stream_socket_client 连接到 tcp 服务器。我的问题是,如果我在执行任何额外的 fwrites 之前回显 $client 对象的内容,页面就会挂起。目前,如果我在调用 stream_get_contents 之前发送我的所有请求,它会起作用,但是一旦我调用 stream_get_contents,它就像客户端不再响应一样?如果有任何帮助,我将不胜感激。
**编辑 这是我正在使用的 API: https://www.onlinenic.com/cp_english/template_api/download/ONLINENIC_API2.0.pdf
**编辑
//see full code below
//------Client creation code, precho function
function getTESTClient($address, $port)
{
$client = stream_socket_client("$address:$port", $errno, $errorMessage);
if ($client === false) {
throw new UnexpectedValueException("Failed to connect: $errorMessage");
}
return $client;
}
function precho($s)
{
echo "<pre>";
echo $s;
echo "</pre>";
}
//-------Problem code
//$loginRequest, $domainAvailableRequest, and $logoutRequest - see full code below
//-----------------------------------------
$address = "www.somesite.com";//This is where I would fill in the address
$port = "12345";//This is where I would fill in the port
$client = getTESTClient($address, $port);
//-----------------------------------------
fwrite($client, $loginRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fwrite($client, $domainAvailableRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fwrite($client, $logoutRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fclose($client);
//-------Alternative working code, if I read all responses at once...
//*But I want to be able to read each response individually...
fwrite($client, $loginRequest);
fwrite($client, $domainAvailableRequest);
fwrite($client, $logoutRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fclose($client);
完整代码:
<?php
function getDomainType($ext)
{
$domaintypes = ['com'=>0, 'net'=>0, 'org'=>807, 'biz'=>800, 'info'=>805, 'us'=>806, 'in'=>808,
'mobi'=>903, 'eu'=>902, 'asia'=>905, 'me'=>906, 'name'=>804, 'tel'=>907, 'cc'=>[600,610], 'tv'=>400,
'tw'=>302, 'uk'=>901, 'co'=>908, 'xxx'=>930, 'pw'=>940, 'club'=>740, 'bike'=>2001, 'clothing'=>2002,
'guru'=>2003, 'holdings'=>2004, 'plumbing'=>2005, 'singles'=>2006, 'ventures'=>2007, 'camera'=>2008,
'equipment'=>2009, 'estate'=>2010, 'gallery'=>2011, 'graphics'=>2012, 'lighting'=>2013, 'photography'=>2014,
'construction'=>2015, 'contractors'=>2016, 'site'=>950, 'online'=>951, 'sex'=>936,
'directory'=>2017, 'kitchen'=>2018, 'land'=>2019, 'technology'=>2020, 'today'=>2021, 'diamonds'=>2022,
'enterprises'=>2023, 'tips'=>2024, 'voyage'=>2025, 'careers'=>2026, 'photos'=>2027,
'recipes'=>2028, 'shoes'=>2029, 'cab'=>2030, 'company'=>2031, 'domains'=>2032, 'limo'=>2033,
'academy'=>2034, 'center'=>2035, 'computer'=>2036, 'management'=>2037, 'systems'=>2038,
'builders'=>2039, 'email'=>2040, 'solutions'=>2041, 'support'=>2042, 'training'=>2043, 'camp'=>2044,
'education'=>2045, 'glass'=>2046, 'institute'=>2047, 'repair'=>2048, 'coffee'=>2049, 'florist'=>2050,
'house'=>2051, 'international'=>2052, 'solar'=>2053, 'marketing'=>2054, 'viajes'=>2055, 'farm'=>2056,
'codes'=>2057, 'cheap'=>2058, 'zone'=>2059, 'agency'=>2060, 'bargains'=>2061, 'boutique'=>2062,
'cool'=>2063, 'watch'=>2064, 'works'=>2065, 'expert'=>2066, 'foundation'=>2067, 'exposed'=>2068,
'villas'=>2069, 'flights'=>2070, 'rentals'=>2071, 'cruises'=>2072, 'vacations'=>2073, 'condos'=>2074,
'properties'=>2075, 'maison'=>2076, 'tienda'=>2077, 'dating'=>2078, 'events'=>2079, 'partners'=>2080,
'productions'=>2081, 'community'=>2082, 'catering'=>2083, 'cards'=>2084, 'cleaning'=>2085, 'tools'=>2086,
'industries'=>2087, 'parts'=>2088, 'supplies'=>2089, 'supply'=>2090, 'report'=>2091, 'vision'=>2092,
'fish'=>2093, 'services'=>2094, 'capital'=>2095, 'engineering'=>2096, 'exchange'=>2097, 'gripe'=>2098,
'associates'=>2099, 'lease'=>2100, 'media'=>2101, 'pictures'=>2102, 'reisen'=>2103, 'toys'=>2104,
'university'=>2105, 'town'=>2106, 'wtf'=>2107, 'fail'=>2108, 'financial'=>2109, 'limited'=>2110,
'care'=>2111, 'clinic'=>2112, 'surgery'=>2113, 'dental'=>2114, 'tax'=>2115, 'cash'=>2116,
'fund'=>2117, 'investments'=>2118, 'furniture'=>2119, 'discount'=>2120, 'fitness'=>2121, 'schule'=>2122,
'sexy'=>2500, 'tattoo'=>2501, 'link'=>2502, 'guitars'=>2503, 'gift'=>2504, 'pics'=>2505, 'photo'=>2506,
'christmas'=>2507, 'blackfriday'=>2508, 'hiphop'=>2509, 'juegos'=>2510, 'audio'=>2511, 'click'=>2512,
'hosting'=>2513, 'property'=>2514, 'top'=>770, 'porn'=>932, 'adult'=>934, 'city'=>2129, 'ceo'=>742];
if(isset($domaintypes[strtolower($ext)]))
{
return $domaintypes[strtolower($ext)];
}
return "unknown";
}
function getTCPClient()
{
}
function getTESTClient($address, $port)
{
$client = stream_socket_client("$address:$port", $errno, $errorMessage);
if ($client === false) {
throw new UnexpectedValueException("Failed to connect: $errorMessage");
}
return $client;
}
function uniqueInvoiceID()
{
$legend = "0123456789";
$len = 22;
$result = "";
for($i=0;$i<$len;$i++)
{
$result .= $legend[rand(0,9)];
}
return "client".$result;
}
function precho($s)
{
echo "<pre>";
echo $s;
echo "</pre>";
}
$clid = "135610";//OnlineNic's test account username
$clpass = "654123";//OnlineNic's test account password
$cltrid = uniqueInvoiceID();//Client Record ID/Invoice
echo $cltrid."<br><br>";
//md5(clid + md5(clpass) + cltrid + “login”)
$checkSumLogin = md5($clid.md5($clpass).$cltrid."login");//Checksum
$checkSumLogout = md5($clid.md5($clpass).$cltrid."logout");//Checksum
$loginRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
<request>
<category>client</category>
<action>Login</action>
<params>
<param name=\"clid\">$clid</param>
</params>
<cltrid>$cltrid</cltrid>
<chksum>$checkSumLogin</chksum>
</request>";
$logoutRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
<request>
<category>client</category>
<action>Logout</action>
<params>
<param name=\"clid\">$clid</param>
</params>
<cltrid>$cltrid</cltrid>
<chksum>$checkSumLogout</chksum>
</request>";
$checkDomain = "somedomain.com";
$ext = "com";
$dType = getDomainType($ext);
$requestID = uniqueInvoiceID();
$domainAvailChecksum = md5($clid.md5($clpass).$requestID."checkdomain".$dType.$checkDomain);
$domainAvailableRequest = "<?xml version=\"1.0\"?>
<request>
<category>domain</category>
<action>CheckDomain</action>
<params>
<param name=\"domaintype\">$dType</param>
<param name=\"domain\">$checkDomain</param>
</params>
<cltrid>$requestID</cltrid>
<chksum>$domainAvailChecksum</chksum>
</request>";
$client = getTESTClient("tcp://ote.onlinenic.com", "30009");
fwrite($client, $loginRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fwrite($client, $domainAvailableRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fwrite($client, $logoutRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fclose($client);
?>
最佳答案
stream_get_contents 的第二个参数是$maxlength,即要读取的最大字节数。如果未设置(或传递默认值 -1),将读取整个流,直到流的末尾。
这意味着当流被另一端关闭时,stream_get_contents 将继续从流中读取所有数据,直到没有更多数据为止。 (stream_get_contents 不知道你的协议(protocol)的细节,所以它不知道在服务器“一个响应”之后“应该”停止读取;它没有任何概念这甚至意味着。)
这意味着,如果您的 TCP 连接上有一个查询-响应协议(protocol),您将必须 stream_get_contents() exactly 您想要接收的数据长度(如果您确切知道响应的大小),或者您将不得不从服务器读取数据并自行处理。
具体如何操作将在很大程度上取决于您的协议(protocol)。如果是面向行的,可以使用fgets($client) 一次检索一行。如果是二进制协议(protocol),可以使用stream_get_contents($client, $sizeOfYourPacket)。
由于您有一个基于 XML 的协议(protocol),您可能希望创建一个新函数来处理读取响应并理解 XML,以便它知道要读取多少数据以及何时可以将响应(可能已经处理)发送回你的申请。
如果没有实际的凭据,则很难了解服务器的具体行为,因此除此之外,您将不得不进行试验。
关于如果多次调用,来自 TCP 客户端的 PHP stream_get_contents 会挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34827770/
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby数组,我们在StackOverflow上找到一
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
如果我使用ruby版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
我试图在我的网站上实现使用Facebook登录功能,但在尝试从Facebook取回访问token时遇到障碍。这是我的代码:ifparams[:error_reason]=="user_denied"thenflash[:error]="TologinwithFacebook,youmustclick'Allow'toletthesiteaccessyourinformation"redirect_to:loginelsifparams[:code]thentoken_uri=URI.parse("https://graph.facebook.com/oauth/access_token
啊,正则表达式有点困惑。我正在尝试删除字符串末尾所有可能的标点符号:ifstr[str.length-1]=='?'||str[str.length-1]=='.'||str[str.length-1]=='!'orstr[str.length-1]==','||str[str.length-1]==';'str.chomp!end我相信有更好的方法来做到这一点。有什么指点吗? 最佳答案 str.sub!(/[?.!,;]?$/,'')[?.!,;]-字符类。匹配这5个字符中的任何一个(注意,。在字符类中并不特殊)?-前一个字符或组