먼저, 나는 읽었다.네트워크 네임스페이스에 관한 훌륭한 기사입니다.그래서 저는 네트워크 네임스페이스의 기능과 구성 방법을 어느 정도 알고 있습니다.
내가 직면하고 있는 실제 문제는 다음과 같습니다.
- 실제 컴퓨터에서 LAN 모드로 일부 Valve 게임 서버(CS, CS:GO, TF2)를 실행하고 싶습니다. 따라서 LAN의 모든 클라이언트가 LAN의 모든 서버를 나열하기를 원합니다. 이는 ip:port에 수동으로 연결하는 것과 비교할 때 최상의 사용자 경험이기 때문입니다.
- 클라이언트 소프트웨어는 포트 27015 - 27020에 브로드캐스팅하여 LAN 서버를 찾습니다. 따라서 서버를 실행하는 데 사용할 수 있는 포트는 총 6개입니다. 그렇지 않으면 서버가 LAN 브라우저에 나열되지 않습니다. 하지만 서버가 6개 이상이므로 동일한 물리적 서버에 1개 이상의 IP를 사용해야 합니다. 실제 계획은 게임당 1개의 IP를 보유하는 것입니다.
- 반복해서 말하지만 게임 서버에 특정 IP에 바인딩하라고 지시할 수 없습니다. 그렇게 하면 서버가 LAN 서버처럼 실행되도록 명시적으로 지시하더라도 클라이언트의 LAN 브라우저에 나열되지 않기 때문입니다.
(CS 1.6, CSGO 또는 TF2 서버를 실행하려는 사람들은 여기에서 "+ip <ip 주소>" 문제를 인식할 수 있습니다)
게임 서버에 특정 IP 주소에 바인딩하도록 지시할 수 없기 때문에 여러 개의 IP를 사용하여 문제를 해결할 수 없습니다. 소프트웨어는 항상 기본 IP를 사용하므로 작동하지 않습니다. (포트 충돌 또는 소프트웨어가 27020개 이상의 포트를 점유하여 LAN 브라우저에서 서버가 보이지 않게 됨)
저는 네트워크 네임스페이스(게임당 1개의 네트워크 네임스페이스)를 사용하여 이 문제를 해결하고 싶습니다.
- "csgo" 네트워크 네임스페이스에서 CSGO 인스턴스 5개를 실행하겠습니다. (27015 - 27019)
- "tf2" 네트워크 네임스페이스에서 TF2 인스턴스 1개를 실행하겠습니다. (27015)
- "cs16" 네트워크 네임스페이스에서 CS 1.6 인스턴스 2개를 실행하겠습니다. (27015 - 27016)
네임스페이스에서 게임 소프트웨어를 실행할 것이기 때문에 소프트웨어는 1개의 IP만 보고 자동으로 해당 IP를 채택합니다. (글쎄, 그게 내 생각이야!).
총 4개의 네트워크 네임스페이스("default", "csgo", "tf2" 및 "cs16")가 있습니다. 구성은 다음과 같습니다.
- eth0 / 192.168.0.160 ("default" ns, internet access)
- veth0:0 / 192.168.0.161 ("default" ns) <======> veth0:1 / 192.168.0.171 ("csgo" NS)
- veth1:0 / 192.168.0.162 ("default" ns) <======> veth1:1 / 192.168.0.172 ("tf2" NS)
- veth2:0 / 192.168.0.163 ("default" ns) <======> veth2:1 / 192.168.0.173 ("cs16" NS)
이제 문제는 이것이 작동할 수 있는가 하는 것입니다. "csgo" 네임스페이스에서 CSGO 서버 소프트웨어를 실행하는 경우 LAN 서버의 공용 IP는 192.168.0.171입니까? 아니면 192.168.0.160인가요? 아니면 192.168.0.161일까요? 위에서 언급한 것처럼 9개의 서버가 모두 LAN 브라우저에 나타나도록 하려면 각 게임에 별도의 IP 주소를 할당해야 합니다.
그렇지 않다면 실제로 네트워크 네임스페이스를 사용하여 이 문제를 해결할 수 있습니까?
답변1
애플리케이션을 특정 IP 주소에 바인딩하는 것은 매우 어려운 문제입니다. 모든 애플리케이션이 동일한 것은 아닙니다.SSH바인딩할 IP 주소를 지정할 수 있습니다.-비옵션. 예를 들어 Firefox와 Chrome은 이에 영향을 받지 않습니다.
다행히도 해결책이 있습니다:이 남자이미 편집됨바인딩 파일시스템 라이브러리를 사용하면 명령줄에서 바인드 주소를 다음과 같이 지정할 수 있습니다.
$ BIND_ADDR="192.0.2.100" LD_PRELOAD=/usr/lib/bind.so firefox
미리 로드하여제본공유 객체를 사용하면 다르게 바인딩할 인터페이스의 시스템 버전을 선택하지 않아도 됩니다.
이는 여러 네트워크 공간을 동시에 실행하는 것보다 훨씬 쉽고 시스템 리소스를 훨씬 적게 사용합니다.
위의 웹페이지에서는 모듈을 컴파일하는 방법과이 링크사전 컴파일된 32비트 및 64비트 버전.
(참고: 관심 없으시겠지만 코드를 쉽게 수정하여 특정 항목에 강제로 바인딩할 수 있습니다.포트).
편집하다:
나는 게임이 UDP를 사용할 가능성이 높으며 위의 트릭은 TCP 연결에서만 작동한다는 사실을 완전히 잊었습니다. 이런 종류의 TCP 문제가 있는 사람에게 도움이 될 것이라는 희망으로 답변을 남겨두고 있지만 Timmos에 대한 답변으로는 완전히 쓸모가 없습니다.
내 실수를 만회하기 위해 하나(아마도 여러 개)의 네트워크 네임스페이스를 설정하는 내가 작성한 (매우 간단한!) 스크립트를 전달합니다.
#!/bin/bash
#
# This script will setup a network namespace with a macvlan
# which obtains its IP address via dhclient from the LAN on which the host is
# placed
#
set -x
# It will open an xterm window in the new network namespace; if anything
# else is required, change the statement below.
export XTERM1=xterm
# The script will temporarily activate ip forwarding for you. If you
# do not wish to retain this feature, you will have to issue, at the
# end of this session, the command
# echo 0 > /proc/sys/net/ipv4/ip_forward
# yourself.
###############################################################################
export WHEREIS=/usr/bin/whereis
# First of all, check that the script is run by root:
[ "root" != "$USER" ] && exec sudo $0 "$@"
if [ $# != 2 ]; then
echo "Usage $0 name action"
echo "where name is the network namespace name,"
echo " and action is one of start| stop| reload."
exit 1
fi
# Do we have all it takes?
IERROR1=0
IERROR2=0
IERROR3=0
export IP=$($WHEREIS -b ip | /usr/bin/awk '{print $2}')
export IPTABLES=$($WHEREIS -b iptables | /usr/bin/awk '{print $2}')
export XTERM=$($WHEREIS -b $XTERM1 | /usr/bin/awk '{print $2}')
if [ "x$IP" = "x" ] ; then
echo "please install the iproute2 package"
IERROR1=1
fi
if [ "x$IPTABLES" = "x" ] ; then
echo "please install the iptables package"
IERROR2=1
fi
if [ "x$XTERM" = "x" ] ; then
echo "please install the xterm package"
IERROR3=1
fi
if [[ $IERROR1 == 0 && $IERROR2 == 0 && $IERROR3 == 0 ]]
then
:
else
exit 1
fi
prelim() {
# Perform some preliminary setup. First, clear the proposed
# namespace name of blank characters; then create a directory
# for logging info, and a pid file in it; lastly, enable IPv4
# forwarding.
VAR=$1
export NNSNAME=${VAR//[[:space:]]}
export OUTDIR=/var/log/newns/$NNSNAME
if [ ! -d $OUTDIR ]; then
/bin/mkdir -p $OUTDIR
fi
export PID=$OUTDIR/pid$NNSNAME
echo 1 > /proc/sys/net/ipv4/ip_forward
}
start_nns() {
# Check whether a namespace with the same name already exists.
$IP netns list | /bin/grep $1 2> /dev/null
if [ $? == 0 ]; then
echo "Network namespace $1 already exists,"
echo "please choose another name"
exit 1
fi
# Here we take care of DNS
/bin/mkdir -p /etc/netns/$1
echo "nameserver 8.8.8.8" > /etc/netns/$1/resolv.conf
echo "nameserver 8.8.4.4" >> /etc/netns/$1/resolv.conf
# The following creates the new namespace, and the macvlan interface
$IP netns add $1
$IP link add link eth0 mac$1 type macvlan mode bridge
# This assigns the macvlan interface, mac$1, to the new
# namespace, asks for an IP address via a call to dhclient,
# brings up this and the (essential) lo interface,
# creates a new terminal in the new namespace and
# stores its pid for the purpose of tearing it cleanly, later.
$IP link set mac$1 netns $1
$IP netns exec $1 /sbin/dhclient -v mac$1 1> /dev/null 2>&1
$IP netns exec $1 $IP link set dev lo up
$IP netns exec $1 su -c $XTERM $SUDO_USER &
$IP netns exec $1 echo "$!" > $PID
}
stop_nns() {
# Check that the namespace to be torn down really exists
$IP netns list | /bin/grep $1 2>&1 1> /dev/null
if [ ! $? == 0 ]; then
echo "Network namespace $1 does not exist,"
echo "please choose another name"
exit 1
fi
# This kills the terminal in the separate namespace and
# removes the file and the directory where it is stored.
/bin/kill -TERM $(cat $PID) 2> /dev/null 1> /dev/null
/bin/rm $PID
/bin/rmdir $OUTDIR
$IP netns del $1
# This deletes the file and direcotory connected with the DNSes.
/bin/rm /etc/netns/$1/resolv.conf
/bin/rmdir /etc/netns/$1
}
case $2 in
start)
prelim "$1"
start_nns $NNSNAME
;;
stop)
prelim "$1"
stop_nns $NNSNAME
;;
reload)
prelim "$1"
stop_nns $NNSNAME
prelim "$1"
start_nns $NNSNAME
;;
*)
# This removes the absolute path from the command name
NAME1=$0
NAMESHORT=${NAME1##*/}
echo "Usage:" $NAMESHORT "name action,"
echo "where name is the name of the network namespace,"
echo "and action is one of start|stop|reload"
;;
esac
기본 인터페이스가 호출된다고 가정합니다.이더넷 0(호출 방법이 다른 경우 그에 따라 단일 참조를 변경하고)맥에버랜드인터페이스, 이는 스크립트를 사용할 수 있음을 의미합니다.오직이더넷 연결이 있습니다. 또한 네트워크 브리지를 사용할 필요가 없습니다.
다음과 같이 별도의 네트워크 네임스페이스를 시작/중지할 수 있습니다.신경망, 그러나 원하는 대로 호출할 수 있습니다):
nns network_namespace_1 start
nns network_namespace_2 stop
각 macvlan 인터페이스는 LAN DHCP 서버에서 IP 주소를 가져오므로 로컬 DHCP 서버가 허용하는 만큼 다양한 네트워크 네임스페이스를 가질 수 있습니다. 동일한 이름의 네트워크 네임스페이스가 이미 존재하는 경우 다른 이름을 선택해야 합니다.
모든 네트워크 네임스페이스는 서로 통신할 수 있습니다.패턴 브릿지생성 명령의 옵션. 이 스크립트는xterm새로운 네트워크 네임스페이스의 터미널(나는xterm, 그렇지 않은 경우 스크립트 상단에서 이를 변경하여 xterm에서 애플리케이션을 시작할 수 있습니다.
디버깅 옵션을 꺼두었습니다.세트-x, 스크립트에서 일부 초기 문제를 해결하는 데 도움이 될 수 있습니다. 완료되면 해당 줄을 삭제하면 됩니다.
건배.