初心者向けのPythonプログラムのDreamプログラム

ほとんどの初心者のPythonプログラマーは、自分のチャットを病理学的に書き込もうとします。 また、GUIを使用する場合、このプログラムは究極の夢です。



導入のようなもの



最初に、どのくらいの規則をタスクに導入しましょう-許可されたブロードキャストUDPパケットを使用してローカルネットワークのチャットを作成します。 問題を簡単に解決するために、TkinterライブラリをGUIとして使用することも決定します( 通常 、Linuxディストリビューションではそのまま使用できます。Windows用の公式Pythonビルドでも標準です)。



ネットワーク名



Pythonでのソケットの操作はプラットフォームに依存しません(概して、PyS60の下でも、この例では有効なネットワークコードを取得します)。



チャットには、ブロードキャストUDPパケットを使用することにしました。 それらを使用する理由の1つは、サーバーの使用を拒否する機能でした。 プログラムでもう1つ規約を受け入れる必要があります。ポート番号です。11719に等しくする必要があります。まず、これは素数です(すでにたくさんあります)。 そして、第二に、このポートは、IANAの公式情報によると、忙しくありません。



コンソールを受信するメッセージでコンソールを喜ばせるリスニングソケットを作成します。



import socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.bind(('0.0.0.0',11719)) while 1: message = s.recv(128) print (message)
      
      







ソケットで、プロパティSO_REUSEADDR(いくつかのアプリケーションがソケットを「リッスン」できるようにする)とSO_BROADCAST(パケットがブロードキャストされることを示す)を重要な真理に設定します。 実際、一部のシステムでは、これらの行がなくてもスクリプトは機能しますが、これらのプロパティを明示的に指定する方が適切です。

盗聴のために、アドレス「0.0.0.0」に接続します-これは、すべてのインターフェースが一般的にリッスンされることを意味します。 住所フィールドに空の引用符を指定することもできますが、住所を明示的に指定することをお勧めします。



また、ネットワークのブロードキャスト「スニフ」を作成します(最初のプログラムをチェックするため)。



 import socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) while 1: sock.sendto('broadcast!',('255.255.255.255',11719))
      
      







送信部分に関しては、SO_BROADCASTオプションのみが必要です(ただし、現在ではすべてのプラットフォームで必要です)。sendto()メソッドを使用して、ネットワーク経由でパケットを送信します。 CTRL + Cを使用してネットワークフラッドを停止したら、インターフェイスの説明に進みます。



窓、窓、窓



Tkinterはおそらく、Pythonでウィンドウインターフェイスを整理するための最も単純なライブラリの1つです(Pythonの作成者によると、最も信頼性が高く安定しているライブラリの1つです)。 しかし、初心者のピトンガイドにとって、主なポイントは、このライブラリがシンプルであることです。



必要なサイズのウィンドウを指定されたタイトルで取得するには、数行のコードのみが必要です。



 from Tkinter import * tk=Tk() tk.title('MegaChat') tk.geometry('400x300') tk.mainloop()
      
      







すべては問題ありませんが、さまざまなサイズのウィンドウのギャラリーではなく、チャットを作成しています。 そのため、ウィンドウにはチャットログ、ニックネームを示すフィールド、入力するメッセージテキストなどの要素も必要です。 メッセージフィールド自体がEnterキーを押すことに応答する場合は、送信ボタンを省くことができます。



問題の解決は思ったより簡単です。 チャットログには、テキストウィジェットを使用でき、他の2つのエントリには使用できます。 フォームに要素を配置するために、自動パッカーパックを使用します。これは、明示的に指示された指示にのみ従い、要素を配置する方法でのみ彼に知られています。 ただし、ウィジェットをアタッチする側、ウィジェットをどの方向に展開するか、その他のレイアウトオプションを指定できます。



 from Tkinter import * tk=Tk() tk.title('MegaChat') tk.geometry('400x300') log = Text(tk) nick = Entry(tk) msg = Entry(tk) msg.pack(side='bottom', fill='x', expand='true') nick.pack(side='bottom', fill='x', expand='true') log.pack(side='top', fill='both',expand='true') tk.mainloop()
      
      







そして、プログラムデータとのインターフェース接続はどうですか? または、バックグラウンドで実行されるプロシージャを取得する方法は? まあ、EntryはStingVarsに関連付けることができます(ウィジェットデザイナーでtextvariableプロパティを指定することにより)。 バックグラウンドプロシージャを開始するために、Tkinterにはafterメソッド(<time in ms>、<function>)があります。 このプロシージャの実行の終了時に初期化を指定すると、プログラムの実行中にプロシージャが継続的に実行されます。

いくつかのキーストロークと我々は得る:



 from Tkinter import * tk=Tk() text=StringVar() name=StringVar() name.set('HabrUser') text.set('') tk.title('MegaChat') tk.geometry('400x300') log = Text(tk) nick = Entry(tk, textvariable=name) msg = Entry(tk, textvariable=text) msg.pack(side='bottom', fill='x', expand='true') nick.pack(side='bottom', fill='x', expand='true') log.pack(side='top', fill='both',expand='true') def loopproc(): print ('Hello '+ name.get() + '!') tk.after(1000,loopproc) tk.after(1000,loopproc) tk.mainloop()
      
      







コンソールで挨拶が行われました。 ニックネームを変更することにより、入力フィールドと変数間の関係が完全に機能することを確認できます。 Enterキーを押して、ユーザーがメッセージをプログラムに転送する可能性を認識します。 これは、ウィジェットのbind(<action>、<function>)メソッドを使用してさらに簡単に実装されます。 考慮する必要があるのは、関数がイベントパラメータを受け入れる必要があることだけです。 まず、コンソールからログフィールドにアクションを転送します。 取得するもの:



 from Tkinter import * tk=Tk() text=StringVar() name=StringVar() name.set('HabrUser') text.set('') tk.title('MegaChat') tk.geometry('400x300') log = Text(tk) nick = Entry(tk, textvariable=name) msg = Entry(tk, textvariable=text) msg.pack(side='bottom', fill='x', expand='true') nick.pack(side='bottom', fill='x', expand='true') log.pack(side='top', fill='both',expand='true') def loopproc(): log.insert (END,'Hello '+ name.get() + '!\n') tk.after(1000,loopproc) def sendproc(event): log.insert (END,name.get()+':'+text.get()+'\n') text.set('') msg.bind('<Return>',sendproc) tk.after(1000,loopproc) tk.mainloop()
      
      







ほぼ完了しました...



そして、記事の第1部と第2部のプログラムを結合することはまだ残っているようで、すぐにチャットができます。 さて、試してみましょう。 ただし、送信したメッセージは特に表示しません-ブロードキャストトラフィックを聞くと受信するためです。



 import socket from Tkinter import * tk=Tk() s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.bind(('0.0.0.0',11719)) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST,1) text=StringVar() name=StringVar() name.set('HabrUser') text.set('') tk.title('MegaChat') tk.geometry('400x300') log = Text(tk) nick = Entry(tk, textvariable=name) msg = Entry(tk, textvariable=text) msg.pack(side='bottom', fill='x', expand='true') nick.pack(side='bottom', fill='x', expand='true') log.pack(side='top', fill='both',expand='true') def loopproc(): message = s.recv(128) log.insert(END,message) tk.after(1,loopproc) def sendproc(event): sock.sendto (name.get()+':'+text.get(),('255.255.255.255',11719)) text.set('') msg.bind('<Return>',sendproc) tk.after(1,loopproc) tk.mainloop()
      
      







しかし、奇跡は起こりませんでした。 プログラムは、入ってくるパッケージを待ってしっかりと立ち上がった。 バックグラウンドスレッドはそれほどバックグラウンドではないことが判明し、プログラムの残りの部分を継続するために終了することがあります。 これを実現するには、リスニングソケットを非ブロックモードに切り替えて、ソケットが空のときにエラーメッセージを受け取らないように、このコードをtryで囲みます。



 import socket from Tkinter import * tk=Tk() s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.bind(('0.0.0.0',11719)) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST,1) text=StringVar() name=StringVar() name.set('HabrUser') text.set('') tk.title('MegaChat') tk.geometry('400x300') log = Text(tk) nick = Entry(tk, textvariable=name) msg = Entry(tk, textvariable=text) msg.pack(side='bottom', fill='x', expand='true') nick.pack(side='bottom', fill='x', expand='true') log.pack(side='top', fill='both',expand='true') def loopproc(): s.setblocking(False) try: message = s.recv(128) log.insert(END,message+'\n') except: tk.after(1,loopproc) return tk.after(1,loopproc) return def sendproc(event): sock.sendto (name.get()+':'+text.get(),('255.255.255.255',11719)) text.set('') msg.bind('<Return>',sendproc) tk.after(1,loopproc) tk.mainloop()
      
      







「そして、ファイルを変更します...」



純粋に理論的に得られたコードは実行可能ですが、重大な欠点があります-デフォルトではメッセージ入力フィールドがすぐに選択されず、キリル文字に問題がある可能性があり、ログ自体はスクロールダウンしません。 これらのすべての問題の解決策は、次のリストから見ることができます(キリル文字の問題が解決された場所を強調しましたが、残りは明白であることを望みます)



 # -*- coding: utf-8 -*- import socket from Tkinter import * #    reload(sys) sys.setdefaultencoding('utf-8') #----------------------------- tk=Tk() s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.bind(('0.0.0.0',11719)) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST,1) text=StringVar() name=StringVar() name.set('HabrUser') text.set('') tk.title('MegaChat') tk.geometry('400x300') log = Text(tk) nick = Entry(tk, textvariable=name) msg = Entry(tk, textvariable=text) msg.pack(side='bottom', fill='x', expand='true') nick.pack(side='bottom', fill='x', expand='true') log.pack(side='top', fill='both',expand='true') def loopproc(): log.see(END) s.setblocking(False) try: message = s.recv(128) log.insert(END,message+'\n') except: tk.after(1,loopproc) return tk.after(1,loopproc) return def sendproc(event): sock.sendto (name.get()+':'+text.get(),('255.255.255.255',11719)) text.set('') msg.bind('<Return>',sendproc) msg.focus_set() tk.after(1,loopproc) tk.mainloop()
      
      







PSそして忘れないでください-Pythonの長さは9-10メートルに達することができます。



All Articles