有天晚上,平常幫忙測試的那個朋友有上線,想想沒事就請他幫忙測一下。

為了簡化測試內容,我改了一下指令,設定連線ip為讀取一個文件的內容,這樣每次開就不用重新輸入(從此可見我有多懶 XD)。

稍微教他一下操作方式,馬上就開始連線了,我大概可以預知結果是如何,因為我的NAT有開轉發功能(請看上一篇),所以我會被他的測試訊息洗板。他傳來了他的IP,我打開文件,輸入,存檔,再來Shift+F12執行,小黑窗再次出現在我眼前,

「正在連接...」

我向後仰,等著視窗被洗板,突然...

「'test,lancat,153.74.53.46,52876'

   'test,lancat,153.74.53.46,52876'

   已連接」

我愣住了,這不是想像中的樣子啊!

我快速的在鍵盤上打字,

「看的到嗎?」

「<153.74.53.46,52876>測試」

欸欸欸欸欸欸欸??????

那個是訊息,是他傳給我的訊息,不會吧為什麼?

「你看的到嗎?我看的到」

「<153.74.53.46,52876>。。。」

「喔耶!!!」

當下我以為成功了,真的是興奮感瞬間爆發,努力了這麼久,終於成功了!

「1+2=?」我傳

沒有回音,過了一會兒

「<153.74.53.46,52876>3.1415926.........」

嗯?怎麼是圓周率?

我突然有點懷疑到底是不是成功了,打開FB,

「欸你有收到嗎?」

「我什麼都沒看到。」

我被重擊,搞了半天,根本沒有成功,只是單方面的收到他訊息...

跟他說明了下,便繼續回到台下檢查程式,有幾個我不解的地方,因為如果他收不到我的訊息,就應該會不停的洗板下去才對啊!

除非,他收的到。

這下有趣了,在什麼樣的狀況時,我能夠收到他,而他既能收到我的回覆又不能收到我的訊息呢?我仔細看著剛才的紀錄,「153.74.53.46,52876...欸等等,52876是哪來的?」

我的Server預設是4啊,怎麼收到的訊息是從52876這個port來的呢?(有關port請看起步1、2),我檢查程式碼,發現我負責發送訊息的socket物件跟接收的是不一樣的!

「難道,打洞還需要是同一個port嗎?」

我改變了程式碼,將程式所有的發送接收統一由同一個socket來負責,並且固定綁定(bind)到4。

import socket,_thread,time

def server(ADDR,ip):                        #伺服器程式
	global mode,data                        #讀取全域變數
	s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)#建立socket物件
	s.bind(ADDR)                            #綁定IP
	print(ADDR)
	addr = ip,4                             #設定目的位址
	_thread.start_new_thread(test,(s ,addr,ADDR))#開啟新線程不停傳送訊息到對方
	data , addr = s.recvfrom(1024)          #讀取收到的訊息
	mode = False                            #利用全域變數讓另一個線程
	print(data)
	s.sendto('ok'.encode('UTF-8'),addr)     #發送訊息"ok"給對方
	s.sendto(data,(addr[0],4))
	_thread.start_new_thread(user,(s ,addr))#開啟新線程來讀取使用者輸入並發送
	while True:
		data,addr = s.recvfrom(1024)        #等待接收訊息
		print (str(addr)+data.decode('UTF-8')) #印出訊息內容
	s.close
def user(s,addr):                           #發送訊息給對方的函數
	while True:
		data=input()                        #讀取使用者輸入
		if data == 'end':                   #如果輸入"end"就結束
			break
		data=data.encode('UTF-8')
		s.sendto(data,addr)                 #發送訊息
	s.close
def test(s,addr,ADDR):                      #不停發送信息的函數
	global mode#讀取全域變數
	global data
	if mode:
		print('準備連接'+str(addr))
		x = 0
		while mode and x <= 1000:   #重複執行直到server說停或者過了100秒
			s.sendto(data,addr)
			time.sleep(0.1)
			x+=1
		if mode:                    #判斷是否成功
			print('連線失敗')
		else:
			print('已連接')
HOST,PORT = socket.gethostname(),4  #取得自己的ip
HOST = socket.gethostbyname(HOST)
ADDR = (HOST,PORT)
mode = True
data = ('test,'+'lancat,'+str(ADDR[0])+','+str(ADDR[1])).encode()
#預設發送信息,內容無意義
time.sleep(0.5)
f=open('C:\\ip.txt','r')            #讀取對方ip
ip = f.read()
f.close()
server(ADDR,ip)                     #啟動server函數

這次更長了,剛才稍微看了一下,發現還有一些廢話...,沒測試過不敢放上程式碼,所以照舊。

大概跟大家講重點,就是這次主線程是server,不像上次是server和user一起開始,並且user和test函數使用的socket都是server創造並綁定的(就是那個s),什麼意思呢?代表不管是傳送還是接收都是同一個port負責,據我推論,之前之所以失敗,因為test發送過去被對方server接收並回傳ok,所以洗板結束,但是可能連接的只有單方面,例如我朋友的訊息連到我的server,所以這裡就通了,但是我的user並沒有連到他的server,所以我可以接收他的,但他收不到我的,至於為什麼我可以一開始接收?因為我NAT有設定過!

這下子都真相大白了!我立馬再找他測試。

「1+2=?」

<153.74.53.46,4> 3」

這次是真的成功了。

 

後記:這次的文章比較難寫,因為太多抽象的概念,而且很多因為是自己領悟的不知道真的專有名詞是什麼,希望大家能看得懂。XD

 

文章標籤
全站熱搜
創作者介紹
創作者 Cat Lan 的頭像
Cat Lan

Lancat Server 懶貓伺服器

Cat Lan 發表在 痞客邦 留言(0) 人氣(47)