質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Socket.IO

Socket.IOはNode.js上で動くライブラリであり、すべてのブラウザとモバイルデバイスでリアルタイムのアプリを作動させる事を目的としています。

TCP

TCP(Transmission Control Protocol)とは、トランスポート層のプロトコルで、コネクション型のデータサービスです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

2770閲覧

pythonのソケット通信はメッセージを送るごとにアドレス、ポート番号など毎回接続しないといけないものですか?

m-hana

総合スコア10

Socket.IO

Socket.IOはNode.js上で動くライブラリであり、すべてのブラウザとモバイルデバイスでリアルタイムのアプリを作動させる事を目的としています。

TCP

TCP(Transmission Control Protocol)とは、トランスポート層のプロトコルで、コネクション型のデータサービスです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/09/26 07:58

編集2021/09/26 08:40

pythonでGUI制御のソケット通信をしたいです。
GUIで接続ボタンを押したときにコネクトして、それ以降ボタンを押したときにメッセージを送りたいという場合、一回で接続が切れてしまいます。
ボタンを押すごとに毎回コネクトするのは普通のことなのでしょうか?
切断せずメッセージは送る事はできるのでしょうか?
以下テストで作りました。
socket_server.py をコマンドプロンプトで立ち上げてから、
socket_client.py をダブルクリックで立ち上げてください。動作環境は winndows10 で、動作確認済です。
接続が一回で切れてしまいます。

これで正解という事なら問題ないんですが、、、
正解かどうかがわかりません。ご教授お願いします。


追記です。
with文の問題という指摘がございましたので、socket_client.py を with文を使わないでエラーになってしまうコードに編集しなおしました。接続ボタンを毎回おして接続しなおさないと、メッセージを連続でおくれません。
ソケット通信はこういうものなのでしょうか?
メッセージごとに接続しないといけないものですか?
ご教授お願いします。

socket_serber.py

import socket PORT = 50000 BUFFER_SIZE = 1024 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(('127.0.0.1', PORT)) s.listen() while True: (connection, client) = s.accept() try: data = connection.recv(BUFFER_SIZE) print(data.decode(), client) finally: connection.close()

socket_client.py

import tkinter as tk from tkinter import ttk from tkinter import messagebox import socket def connect_func(): global server_address global sock # エントリーボックスの値を取得 serverName = '127.0.0.1' port = 50000 server_address = (serverName, port) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(server_address) def close_func(): sock.clse() def send_func(text): try: sock.send(text.encode()) except: # エラー通知 messagebox.showerror("エラーでござる...") ### GUI ### root = tk.Tk() # ウインドウ名 root.title("接続テスト") # メニューバーの作成 menubar = tk.Menu(root) root.configure(menu = menubar) # File メニュー filemenu = tk.Menu(menubar, tearoff = 0) menubar.add_cascade(label = "ファイル", menu = filemenu) filemenu.add_command(label = "終了", command = lambda: root.destroy()) # ラベルフレーム frame1 = ttk.Labelframe(root, text = "接続先", padding = 10) connect_btn = tk.Button(frame1, text="接続", command = connect_func) connect_btn.pack() close_btn = tk.Button(frame1, text="切断", command = close_func) close_btn.pack() frame1.pack(padx=10, pady=10, anchor=tk.W) # ボタン frame2 = tk.Frame(root) btn1 = tk.Button(frame2, width=20, height=4, text="おはよう", command= lambda: send_func("おはよう")).grid(row = 1, column = 0, padx = 10, pady = 10) btn2 = tk.Button(frame2, width=20, height=4, text="こんにちは", command= lambda: send_func("こんにちは")).grid(row = 1, column = 1, padx = 10, pady = 10) btn3 = tk.Button(frame2, width=20, height=4, text="こんばんは", command= lambda: send_func("こんばんは")).grid(row = 2, column = 0, padx = 10, pady = 10) frame2.pack() # ウインドウサイズの固定 root.resizable(width = False, height = False) root.mainloop()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

提示コードのsocket_serber.pyにおいて、ソケットに対してwith文を使っている部分は問題ありません。
しかしサーバー、クライアントともに通信毎にコネクションをcloseしてしまっているのが問題です。
ただ、closeを呼ばないように修正しただけではだめです。

そもそもサーバー、クライアントいずれも通信処理部分のコード全体がおかしいので
socket --- 低水準ネットワークインターフェース使用例を参考に書き直してください。
そのさい、クライアント側ではソケットとコネクションをメンバ変数として保持しておく必要があります。

投稿2021/09/26 08:37

can110

総合スコア38262

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m-hana

2021/09/26 08:45

回答ありがとうございます。リンクの低水準ネットワークをインターフェースの使用例を参考にしてみます。 情報ありがとうございます。
m-hana

2021/09/28 12:28

いろいろためしてみたのですが、やはりGUIでボタンを押すごとに接続が切れてしまうので、送信ボタンを押すごとにコネクトしなおすというやりかたで対処することにします。連打してもちゃんとメッセージが送れるので大丈夫かなと。それよりループで待機しているほうがスペックをくうと思うので、この方法で行きます。 回答いただき、ありがとうございました。勉強になりました!
guest

0

いろいろためしてみたのですが、やはりGUIの送信ボタンを押すごとに接続が切れてしまうので、送信ボタンを押すごとにコネクトしなおすというやりかたで対処することにします。連打してもちゃんとメッセージが送れるので大丈夫かなと。それよりループで待機しているほうがスペックを使うと思うので、この方法で行きます。
回答いただいたみなさま、ありがとうございました。とても勉強になりました!

以下コードになります。

server.py

import socket PORT = 50000 BUFFER_SIZE = 1024 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(('localhost', PORT)) s.listen() while True: (connection, client) = s.accept() try: data = connection.recv(BUFFER_SIZE) print(data.decode(), client) except: print("error!!!")

client.py

import tkinter as tk from tkinter import ttk from tkinter import messagebox import socket import time from datetime import datetime INTERVAL = 3 # ソケット接続時のリトライ待ち時間 RETRY = 5 # ソケット接続時のリトライ回数 class SocketClient(): def __init__(self): self.host = 'localhost' self.port = 50000 self.buffer = 1024 self.socket = None def host_check(self): client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 確認のために一回接続して成功したら閉じる # サーバーとの接続 RETRY の回数だけリトライ for x in range(RETRY): try: client_socket.connect((self.host, self.port)) self.socket = client_socket print('[{0}] server connect -> address : {1}:{2}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), self.host, self.port) ) self.socket.close() self.socket = None break except socket.error: # 接続を確立できない場合、INTERVAL 秒待ってリトライ time.sleep(INTERVAL) print('[{0}] retry after wait{1}s'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), str(INTERVAL)) ) def connect(self): client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: client_socket.connect((self.host, self.port)) self.socket = client_socket print('[{0}] server connect -> address : {1}:{2}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), self.host, self.port) ) except socket.error: # エラー通知 messagebox.showerror("エラーでござる...", "アドレスを入力してください。") # サーバーへコマンド送信関数 def send(self, text): try: self.connect() self.socket.sendall(text.encode()) self.socket.close() self.socket = None except: # エラー通知 messagebox.showerror("エラーでござる...") client = SocketClient() ### GUI ### root = tk.Tk() # ウインドウ名 root.title("接続テスト") # メニューバーの作成 menubar = tk.Menu(root) root.configure(menu = menubar) # File メニュー filemenu = tk.Menu(menubar, tearoff = 0) menubar.add_cascade(label = "ファイル", menu = filemenu) filemenu.add_command(label = "終了", command = lambda: root.destroy()) # ラベルフレーム frame1 = ttk.Labelframe(root, text = "接続先:localhost", padding = 10) connect_btn = tk.Button(frame1, text="接続確認", command= lambda: client.host_check()) connect_btn.pack() frame1.pack(padx=10, pady=10, anchor=tk.W) # ボタン frame2 = tk.Frame(root) btn1 = tk.Button(frame2, width=20, height=4, text="おはよう", command= lambda: client.send("おはよう")).grid(row = 1, column = 0, padx = 10, pady = 10) btn2 = tk.Button(frame2, width=20, height=4, text="こんにちは", command= lambda: client.send("こんにちは")).grid(row = 1, column = 1, padx = 10, pady = 10) btn3 = tk.Button(frame2, width=20, height=4, text="こんばんは", command= lambda: client.send("こんばんは")).grid(row = 2, column = 0, padx = 10, pady = 10) frame2.pack() # ウインドウサイズの固定 root.resizable(width = False, height = False) root.mainloop()

投稿2021/09/29 00:06

編集2021/09/29 00:49
m-hana

総合スコア10

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Pythonでクラス化したらコネクションができなくなったと同様の問題です。

回答も同じです。

with文は、with文を抜け出すときにcloseします。

公式ドキュメント 8.5. with 文に、

7.コンテキストマネージャの exit() メソッドが呼ばれます。

と書かれている処理です。

後で使いたいのであれば、with文を使うべきではありません。

投稿2021/09/26 08:07

ppaul

総合スコア24666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m-hana

2021/09/26 08:43

回答ありがとうございます。with文を使わないコードを追記しました。 やはり一回しかメッセージをおくれません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問