getaddrinfow fails if running process from Python
<p>I try to run 3rd party process (nsqd.exe) from my python script but when I do nsqd fails to bind socket. I've no idea why.</p>

<p>The script I'm using:</p>

<pre><code>import subprocess
import sys

proc = subprocess.Popen(['nsqd.exe', '-tcp-address="127.0.0.1:{}"'.format(sys.argv[1]),
    '-http-address="127.0.0.1:{}"'.format(sys.argv[2])])

print("the commandline is {}".format(proc.args))
proc.wait()
sys.exit(proc.returncode)
</code></pre>

<p>And the output:</p>

<pre><code>D:\bsm.tar\bsm\final\nsqd&gt;python nsqd.py 4150 4151
the commandline is ['nsqd.exe', '-tcp-address="127.0.0.1:4150"', '-http-address="127.0.0.1:4151"']
[nsqd] 2016/09/26 21:41:51.974681 nsqd v0.3.8 (built w/go1.6.2)
[nsqd] 2016/09/26 21:41:51.975681 ID: 864
[nsqd] 2016/09/26 21:41:51.979675 NSQ: persisting topic/channel metadata to nsqd.864.dat
[nsqd] 2016/09/26 21:41:52.004711 FATAL: listen ("127.0.0.1:4150") failed - listen tcp: lookup "127.0.0.1: getaddrinfow: No such host is known.
</code></pre>

<p>If I run that by myself directly everything works fine:</p>

<pre><code>D:\bsm.tar\bsm\final\nsqd&gt;nsqd.exe -tcp-address="127.0.0.1:4150" -http-address="127.0.0.1:4151"
[nsqd] 2016/09/26 21:42:20.093848 nsqd v0.3.8 (built w/go1.6.2)
[nsqd] 2016/09/26 21:42:20.094850 ID: 864
[nsqd] 2016/09/26 21:42:20.095851 NSQ: persisting topic/channel metadata to nsqd.864.dat
[nsqd] 2016/09/26 21:42:20.127984 TCP: listening on 127.0.0.1:4150
[nsqd] 2016/09/26 21:42:20.127984 HTTP: listening on 127.0.0.1:4151
[nsqd] 2016/09/26 21:42:22.111580 NSQ: persisting topic/channel metadata to nsqd.864.dat
[nsqd] 2016/09/26 21:42:22.111580 TCP: closing 127.0.0.1:4150
[nsqd] 2016/09/26 21:42:22.112553 HTTP: closing 127.0.0.1:4151
[nsqd] 2016/09/26 21:42:22.135635 NSQ: closing topics
[nsqd] 2016/09/26 21:42:22.135635 QUEUESCAN: closing
[nsqd] 2016/09/26 21:42:22.135635 LOOKUP: closing
[nsqd] 2016/09/26 21:42:22.135635 ID: closing

D:\bsm.tar\bsm\final\nsqd&gt;
</code></pre>

<p>Maybe somebody have idea what is wrong?</p>

<p>Win10, python352. Running as admin does not help.</p>

<p>Thanks.</p>

<p>Remove the double quotes in your <code>Popen</code> so it becomes:</p>

<pre><code>proc = subprocess.Popen(['nsqd.exe', 
                         '-tcp-address=127.0.0.1:{}'.format(sys.argv[1]), 
                         '-http-address=127.0.0.1:{}'.format(sys.argv[2])
                       ])
</code></pre>

<p>Before passing your command to <code>CreateProcess</code>, Python converts the list to a string using <code>subprocess.list2cmdline</code>: </p>

<pre><code>&gt;&gt;&gt; subprocess.list2cmdline(['nsqd.exe', '-tcp-address="127.0.0.1:4150"', '-http-address="127.0.0.1:4151"'])
'nsqd.exe -tcp-address=\\"127.0.0.1:1234\\" -http-address=\\"127.0.0.1:1234\\"
</code></pre>

<p>nsqd.exe thinks <code>"127.0.0.1</code> is the hostname - hence the failed lookup.</p>

<h2>Additional Information</h2>

<p>The reason the double quotes work on the command line is that they have special meaning when a function such as <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx" rel="nofollow">CommandLineToArgvW</a> is used to split the command line into individual arguments: normally arguments are delimited by whitespace, but when a quoted string is encountered, the quotes are stripped and the entire string becomes one argument.</p>

<p>This is also why Python is \-escaping the quotes: it expects the resultant line to be parsed in the above manner.</p>

<p>If you pass <code>Popen</code> a string rather than a list, <code>list2cmdline</code> will not be called and you should get the same results as removing the double quotes (i.e. it will be like running it from the command line):</p>

<pre><code>proc = subprocess.Popen('nsqd.exe "-tcp-address=127.0.0.1:{}" '
                        '"-http-address=127.0.0.1:{}"'
                        .format(sys.argv[1], sys.argv[2]))
</code></pre>

<p>You can see this illustrated in the following (perhaps contrived) example:</p>

<pre><code>import subprocess
subprocess.Popen('c:\python27\python.exe "--version"')
subprocess.Popen(['c:\python27\python.exe', '"--version"'])
</code></pre>

<p>The first <code>Popen</code> will print the python version. The second will look for a file named <code>"--version"</code>: <code>can't open file '"--version"': [Errno 22] Invalid argument</code></p>

python windows tcp subprocess nsq