【Python】サーバとクライアントのソケット通信を行う

はじめに

Pythonのsocketを使用してサーバとクライアントのソケット通信をやってみたいと思います。

視覚的にわかり易いと思うので、TkinterでGUIを作ります。動作としてはサーバとクライアントが接続された後、サーバ側からクライアント側に設定した任意の文字列を送信すると、クライアント側からサーバ側に設定した任意の文字列を送り返すというシンプルなシーケンスです。

今回はサーバ側もクライアント側も同じPCで動かすので同一のIPアドレスを想定しています。もちろん変更すれば2台のPCでもソケット通信は可能だと思います。



開発環境

  • Windows 10
  • Python 3.10.5



サーバ側のプログラム

プログラム(server.py)は以下です。

import socket
import tkinter
from tkinter import *
import tkinter as tk
import threading

# グローバル
flag_start = False
flag_init_done = False

#ボタンを押した時の処理
def ButtonPush20(e):
	global flag_start
	flag_start = True

#ボタンを押した時の処理
def ButtonPush30(e):
	global flag_send_msg
	flag_send_msg = True

#ボタンを押した時の処理
def ButtonPush50(e):
	global flag_start
	flag_start = False


def Operation():
	print('Operation')
	global flag_start
	global flag_init_done
	global flag_send_msg

	while(1):
		flag_send_msg = False
		if (flag_start==True):
			if (flag_init_done==False):
				print('Start')
				s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
				s.bind((socket.gethostname(), 1234))  # IPとポート番号を指定します
				s.listen(5)
				clientsocket, address = s.accept()
				print('accept')
				print('address = ', address[0])
				label10_01['text'] = address[0]
				flag_init_done = True
			else:
				if (flag_send_msg==True):
					clientsocket.send(bytes(entry30_00.get(), 'utf-8'))
					print('Send')
					msg = clientsocket.recv(1024)
					label40_01['text'] = msg.decode("utf-8")
					print(msg.decode("utf-8"))
					print('passed')
					flag_send_msg = False


if __name__ == '__main__':

	print('Program start.')

	# スレッド
	thread1 = threading.Thread(target=Operation)
	thread1.start()

	ip = socket.gethostbyname(socket.gethostname())
	print(ip)

	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

	######################## tkinter #################################################################################################

	root = tkinter.Tk()
	root.title('Server')

	frame_00 = Frame(root, pady=10, padx=10)
	frame_10 = Frame(root, pady=10, padx=10)
	frame_20 = Frame(root, pady=10, padx=10)
	frame_25 = Frame(root, pady=10, padx=10)
	frame_28 = Frame(root, pady=10, padx=10)
	frame_30 = Frame(root, pady=10, padx=10)
	frame_40 = Frame(root, pady=10, padx=10)

	# ラベル
	label10_00 = tkinter.Label(frame_10, text="クライアントIPアドレス  ", font=("MS明朝", "10"))
	# ラベル
	label10_01 = tkinter.Label(frame_10, text=" ", font=("MS明朝", "10"))
	label10_00.pack(side=tk.LEFT)
	label10_01.pack(side=tk.LEFT)
	frame_10.pack(fill=tk.X)

	# ラベル
	label20_00 = tkinter.Label(frame_20, text="サーバスタート          ", font=("MS明朝", "10"))
	#ボタン作成
	button20_00 = tkinter.Button(frame_20, text="スタート", fg="white", bg="blue", height="2", width="20", font=("MS明朝", "10"))
	label20_01 = tkinter.Label(frame_20, text="", font=("MS明朝", "10"))
	label20_00.pack(side=tk.LEFT)
	button20_00.pack(side=tk.LEFT)
	label20_01.pack(side=tk.LEFT)
	frame_20.pack(fill=tk.X)
	#ボタン処理の割り当て
	button20_00.bind("<Button-1>", ButtonPush20)

	# ラベル
	label30_00 = tkinter.Label(frame_30, text="メッセージ送信          ", font=("MS明朝", "10"))
	#ボタン作成
	button30_00 = tkinter.Button(frame_30, text="送信    ", fg="white", bg="blue", height="2", width="20", font=("MS明朝", "10"))
	# ラベル
	label30_01 = tkinter.Label(frame_30, text="  ", font=("MS明朝", "10"))
	#入力ボックス作成
	entry30_00 = tkinter.Entry(frame_30, width=30, bg="white", justify='center', font=("MS明朝", "10"))
	entry30_00.insert(0, "Sent from server.")
	label30_00.pack(side=tk.LEFT)
	button30_00.pack(side=tk.LEFT)
	label30_01.pack(side=tk.LEFT)
	entry30_00.pack(side=tk.LEFT)
	frame_30.pack(fill=tk.X)
	#ボタン処理の割り当て
	button30_00.bind("<Button-1>", ButtonPush30)

	# ラベル
	label40_00 = tkinter.Label(frame_40, text="受信メッセージ        ", font=("MS明朝", "10"))
	# ラベル
	label40_01 = tkinter.Label(frame_40, text="", font=("MS明朝", "10"))
	label40_00.pack(side=tk.LEFT)
	label40_01.pack(side=tk.LEFT)
	frame_40.pack(fill=tk.X)

	root.mainloop()

threadを使用して並行処理を行います。Operationで押されたボタンの状態をモニタしながら相応の処理を行います。

このプログラムを実行すると、まず以下のようなTkinterのウィンドウが表示されます。「スタート」をクリックすると取得したPCのIPアドレスとポート番号1234でクライアントとの接続を待ちます。

server.pyを実行したときのTkinterのウィンドウ





クライアント側のプログラム

プログラム(client.py)は以下です。

import socket
import tkinter
from tkinter import *
import tkinter as tk
import threading

# グローバル
flag_start = False
flag_init_done = False
flag_send_msg = False
ip = ''

#ボタンを押した時の処理
def ButtonPush20(e):
	global flag_start
	flag_start = True

#ボタンを押した時の処理
def ButtonPush30(e):
	global flag_send_msg
	flag_send_msg = True

#ボタンを押した時の処理
def ButtonPush50(e):
	flag_start = False

def Operation():
	print('Operation')
	global flag_start
	global flag_init_done
	global flag_send_msg
	global ip

	while(1):
		if (flag_start==False):
			flag_start = False
			flag_send_msg = False
			flag_init_done = False
		if (flag_start== True):
			if (flag_init_done==False):
				print('Client start')
				label10_01['text'] = ip
				s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
				s.connect((socket.gethostname(), 1234))  # IPとポート番号を指定します
				flag_init_done = True
			else:
				while (flag_start== True):
					msg = s.recv(1024)
					print('Received')
					print(msg.decode("utf-8"))
					label40_02['text'] = msg.decode("utf-8")
					s.send(bytes(entry30_00.get(), 'utf-8'))


if __name__ == '__main__':

	print('Program start.')

	# スレッド
	thread1 = threading.Thread(target=Operation)
	thread1.start()

	ip = socket.gethostbyname(socket.gethostname())
	print(ip)

	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

	######################## tkinter #################################################################################################

	root = tkinter.Tk()
	root.title('Client')

	frame_00 = Frame(root, pady=10, padx=10)
	frame_10 = Frame(root, pady=10, padx=10)
	frame_20 = Frame(root, pady=10, padx=10)
	frame_25 = Frame(root, pady=10, padx=10)
	frame_28 = Frame(root, pady=10, padx=10)
	frame_30 = Frame(root, pady=10, padx=10)
	frame_40 = Frame(root, pady=10, padx=10)

	# ラベル
	label10_00 = tkinter.Label(frame_10, text="クライアントIPアドレス  ", font=("MS明朝", "10"))
	# ラベル
	label10_01 = tkinter.Label(frame_10, text="", font=("MS明朝", "10"))
	label10_00.pack(side=tk.LEFT)
	label10_01.pack(side=tk.LEFT)
	frame_10.pack(fill=tk.X)

	# ラベル
	label20_00 = tkinter.Label(frame_20, text="クライアントスタート    ", font=("MS明朝", "10"))
	#ボタン作成
	button20_00 = tkinter.Button(frame_20, text="スタート", fg="white", bg="blue", height="2", width="20", font=("MS明朝", "10"))
	label20_01 = tkinter.Label(frame_20, text="", font=("MS明朝", "10"))
	label20_00.pack(side=tk.LEFT)
	button20_00.pack(side=tk.LEFT)
	label20_01.pack(side=tk.LEFT)
	frame_20.pack(fill=tk.X)
	#ボタン処理の割り当て
	button20_00.bind("<Button-1>", ButtonPush20)

	# ラベル
	label30_00 = tkinter.Label(frame_30, text="送信メッセージ      ", font=("MS明朝", "10"))
	# ラベル
	label30_01 = tkinter.Label(frame_30, text="  ", font=("MS明朝", "10"))
	#入力ボックス作成
	entry30_00 = tkinter.Entry(frame_30, width=30, bg="white", justify='center', font=("MS明朝", "10"))
	entry30_00.insert(0, "This is client.")
	label30_00.pack(side=tk.LEFT)
	label30_01.pack(side=tk.LEFT)
	entry30_00.pack(side=tk.LEFT)
	frame_30.pack(fill=tk.X)

	# ラベル
	label40_00 = tkinter.Label(frame_40, text="受信メッセージ  ", font=("MS明朝", "10"))
	# ラベル
	label40_01 = tkinter.Label(frame_40, text="      ", font=("MS明朝", "10"))
	# ラベル
	label40_02 = tkinter.Label(frame_40, text="", font=("MS明朝", "10"))
	label40_00.pack(side=tk.LEFT)
	label40_01.pack(side=tk.LEFT)
	label40_02.pack(side=tk.LEFT)
	frame_40.pack(fill=tk.X)

	root.mainloop()

同様にthreadを使用して並行処理を行います。Operationで押されたボタンの状態をモニタしながら相応の処理を行います。

このプログラムを実行すると、まず以下のようなTkinterのウィンドウが表示されます。



client.pyを実行したときのTkinterのウィンドウ





サーバ側とクライアント側のソケット通信

以下の手順でソケット通信を行います。

  1. server.pyを起動します。
  2. client.pyを起動します。
  3. server.pyのGUIで、スタートボタンを押します。
  4. client.pyのGUIでスタートボタンを押します。サーバと接続が完了するとserver.pyのGUIにクライアント側のIPアドレスが表示されます。
  5. server.pyのGUIで、送信ボタンを押すと、サーバからクライアントにメッセージが送信され、クライアントからサーバにメッセージが送信されます。




© 2025 サニーサイド