As far as I know, when a packet arrives at the NIC, the DMAC will copy the packet to the kernel space. When the DMAC completes its work, it notifies the CPU, and then the CPU copies the data to the user space. Doing so will cause the memory to be read once and to be written twice. I wrote a simple program to simulate this process. This is the code:
# server.py
import socket
import sys
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "70.202.0.116"
port = 12306
server.bind((host, port))
server.listen(5)
while True:
conn,addr = server.accept()
print(conn,addr)
while True:
data = conn.recv(4096)
if not data:
print("client has lost")
conn.close()
break
server.close()
# client.py
import socket
import sys
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "70.202.0.116"
port = 12306
client.connect((host, port))
data = ''
for i in range(4096):
data += 'a'
while True:
client.send(data.encode())
client.close()
My machine has two numa nodes. At the first time, I disabled NIC Multi-Queue by ethtool -L eno1 combined 1, thus there is only one network interrupt left, and set the affanity by ehco 22 > /proc/irq/137/smp_affinity_list. Core 22 is on numa 1. Then I ran server.py. I use pcm-memory to moniter system memory bandwidth, and I got the expected output, the read-write ratio is close to 1:2.
But when I changed the affanity to core 0 which is on numa 0, I got totally different result. The read-write ratio is close to 1:1.
I want to know what does the interrput handler do during this process, why did I get different result?
increase read latency could be because device belongs to different numa_node. Check device where server and client is running belongs to which numa node
# cat /sys/bus/pci/devices/<PCI device>/numa_node
Related
I want to simulate test cross-platform connection failures / timeouts, starting with blocking connect()s:
#!/usr/bin/python3
import socket
s = socket.socket()
endpoint = ('localhost', 28813)
s.bind((endpoint))
# listen for connections, accept 0 connections kept waiting (backlog)
# all other connect()s should block indefinitely
s.listen(0)
for i in range(1,1000):
c = socket.socket()
c.connect(endpoint)
# print number of successfully connected sockets
print(i)
On Linux, it prints "1" and hangs indefinitely (i.e. the behavior I want).
On Windows (Server 2012), it prints "1" and aborts with a ConnectionRefusedError.
On macOS, it prints all numbers from 1 to 128 and then hangs indefinitely.
Thus, I could accept the macOS ignores the backlog parameter and just connect enough sockets for clients to block on new connections.
How can I get Windows to also block connect() attempts?
On Windows, the SO_CONDITIONAL_ACCEPT socket option allows the application to have the incoming connections wait until it's accept()ed. The constant (SO_CONDITIONAL_ACCEPT=0x3002) isn't exposed in the Python module, but can be supplied manually:
s.bind(endpoint)
s.setsockopt(socket.SOL_SOCKET, 0x3002, 1)
s.listen(0)
It's so effective that even the first connect is kept waiting.
On macOS, backlog=0 is reset to backlog=SOMAXCONN, backlog=1 keeps all connections except the first waiting.
I'm debugging a 3rd-party network application and trying to figure out why it reports errors when calling setsockopt with IP_ADD_MEMBERSHIP to set up a multicast group. The application is in C++, but I've written an MWE in python that replicates the same syscalls:
import socket
import struct
ETH0_IP = "192.168.88.85"
ETH0_1_IP = "192.168.88.254"
MULTICAST_IP = "224.0.0.7"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
ip = socket.inet_aton(ETH0_IP)
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, ip)
group = struct.pack("4s4s", socket.inet_aton(MULTICAST_IP), ip)
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, group)
# s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
ip2 = socket.inet_aton(ETH0_1_IP)
s2.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, ip2)
group2 = struct.pack("4s4s", socket.inet_aton(MULTICAST_IP), ip2)
# the second group is added to the first socket so that we can only bind to one socket and read data from it
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, group2)
At the second IP_ADD_MEMBERSHIP call I get error OSError: [Errno 98] Address already in use.
I found out this only happens when ETH0_1_IP is a subinterface of ETH_0_IP. And I'm not sure if this is expected. If it is, is there a way to actually detect this situation and discard subinterfaces of already bound interfaces? Further, would my multicast socket receive data sent to the subinterface if registration for it fails with the above error?
For the sake of completeness:
$ cat /etc/network/interfaces
auto lo
iface lo inet loopback
iface lo inet6 loopback
auto eth0:1
iface eth0:1 inet static
address 192.168.88.254
netmask 255.255.240.0
Linux is tracking your alias interface as the same interface and so rejecting the attempt to re-use the interface.
In a bit more detail, I have run your code successfully on CentOS 7 using two separate physical interfaces with no changes. If I then change the code to use an alias on the same physical address, it fails with the same error that you see.
Digging a little further, I see that if I dump the interface indeces (using SIOCGIFINDEX) for the physical adaptor and the alias, they do indeed have the same index.
If you want to use Python to check this for yourself, have a quick look at https://gist.github.com/firaxis/0e538c8e5f81eaa55748acc5e679a36e for some code (missing imports of ctypes and socket) and then try something like this:
print(Interface(name="eth0").index)
print(Interface(name="eth0:1").index)
I'm currently working on a raspberry pi project for school where I read data from an OBD2 to usb censor in my car.
When I'm using Screen to connect to the serial port everything works fine, but when I try to do it in python the serial.readline() returns an empty string.
Does anybody know how I can retrieve data from the serial port in python?
I've tried about every option available.
import serial
ser = 0
#Function to Initialize the Serial Port
def init_serial():
global ser
ser = serial.Serial()
ser.baudrate = 38400
ser.port = '/dev/ttyUSB0'
ser.timeout = 1
ser.open() #Opens SerialPort
# print port open or closed
if ser.isOpen():
print 'Open: ' + ser.portstr
#Function Ends Here
init_serial()
temp = raw_input('Type what you want to send, hit enter:\r\n')
ser.write(temp) #Writes to the SerialPort
while 1:
bytes = ser.readline() #Read from Serial Port
print bytes #Print What is Read from Port
You may not be sending valid data to get a response. I believe the ODB2 interface uses the AT command set. Sending AT\n may be a good starting point.
I'm using a Bluetooth ODB2 interface and found that the serial baudrate was fixed. Using any other baudrate failed to correctly get data.
I recommend testing from putty or other terminal that supports serial ports, until you get the device to respond correctly. Then use valid settings to troubleshoot your code.
You're not sending a \r\n with your command, ELM327 requires a new line character at the end of a command.
I have a standalone lua script that uses lua sockets to connect to a server via TCP IP. It uses receive call to receive data from that server. It works, however, when I try to stop it with Ctrl+C, one of the two scenarios is happening:
-If there is currently no traffic and receive is waiting, Ctrl+C will have no effect. The program will continue to run, and will have to be terminated by kill.
-If there is traffic, the program will exit with the below printout and with the socket still open and with the server not accepting another connection:
lua: luaSocketTest.lua:15: interrupted!
stack traceback:
[C]: in function 'receive'
luaSocketTest.lua:15: in function 'doWork'
luaSocketTest.lua:22: in main chunk
[C]: ?
I tried using pcall to solve the second scenario, without success. pcall doesn't return, the process still throws the error.
Sample of my program is below:
local socket = require ("socket")
local ip = "localhost"
local port = 5003
function doWork ()
print ("Starting socket: "..ip..":"..port)
client = assert(socket.connect(ip, port))
print ("Socket Accepted")
client:send("TEST TEST")
while 1 do
local byte, err = client:receive (1)
if not err then
print (byte)
end
end
end
while 1 do
local status = pcall(doWork())
print ("EXITED PCALL WITH STATUS: "..tostring(status))
if not status then client:close() end
end
This would be quite a change, but you could employ lua-ev. It allows to add Signal handlers, which is exactly what is required to react to ctrl-c.
local socket = require'socket'
-- make connect and send in blocking mode
local client = socket.connect(ip,port)
client:send('TEST TEST')
-- make client non-blocking
client:settimeout(0)
ev.IO.new(function()
repeat
local data,err,part = client:receive(10000)
print('received',data or part)
until err
end,client:getfd(),ev.READ):start(ev.Loop.default)
local ev = require'ev'
local SIGINT = 2
ev.Signal.new(function()
print('SIGINT received')
end,SIGINT):start(ev.Loop.default)
ev.Loop.default:loop()
I'm trying to send some data in bits from one computer to another one that are on the same network using TCP in Matlab.
Currently this is what I have setup to open the connections. I'm trying to simulate a peer-to-peer connection because they need to send and receive data from each other. It works fine on my local machine when I run it using my IPv4 and IPv6.
%code starts in one file
openRecieve('0.0.0.0', 3000); %accept all connections
openSend('10.32.41.235',3000);
Then I do the same in another file and I can run them i parallel on my machine:
%code starts in other file
openSend('10.32.41.235',3000); %IPv4 of PC
openRecieve('0.0.0.0', 3000); %accept all connections
The IPs are bogus...... This code works on my machine when run with 2 different instances of matlab open. However it doesn't work between 2 different computers.
Code for openReceive:
function connectionServer = openRecieve(client, port)
t = tcpip('0.0.0.0', port, 'NetworkRole', 'Server');
set(t, 'InputBufferSize', 3000000);
% Open connection to the client.
fopen(t);
fprintf('%s \n','Client Connected');
connectionServer = t;
set(connectionServer,'Timeout',.1);
end
Code for openSend:
function connectionSend = openSend(host, port)
d = tcpip(host, port, 'NetworkRole', 'Client');
set(d, 'OutputBufferSize', 3000000); % Set size of receiving buffer, if needed.
%Trying to open a connection to the server.
while(1)
try
fopen(d);
break;
catch
fprintf('%s \n','Cant find Server');
end
end
connectionSend = d;
end
Any help is appreciated.
It is now running although the only thing I changed was the port numbers from 3000 and 3000 to 3000 and 3001.......... Also using only IPv4 was pretty key as my network didn't allow for IPv6.
For anyone trying to write TCP code in Matlab just use '0.0.0.0' for the connection if you don't care who is connecting as it will accept all IPs trying to connect on that port #.
Current code for first file:
sConec = openSend('10.234.24.124', 3000); %IPv4 Address of comp your trying to connect to
rConec = openRecieve('0.0.0.0', 3001); %Accept all connections
Current code for second file:
rConec = openRecieve('0.0.0.0', 3000); %Accept all connections
sConec = openSend('10.109.22.142', 3001); %IPv4 Address of computer your trying to connect to