このページでは Python プログラムとC言語プログラムとでソケット通信を行うプログラムの作り方について説明していきます!
Contents
異なるプログラミング言語間でのソケット通信
実は、別にプログラミング言語が同じであろうが異なろうがソケット通信には関係ありません。なので、”Python で開発したプログラム” と “C言語で開発したプログラム” との間でソケット通信は可能です。そして、このソケット通信により、プログラム間でデータのやり取りをしたり、一方のプログラムから他方のプログラムに指示を出したりするようなことも可能です。もちろん、他のプログラミング言語で開発した場合も同様です。
要は、2つのプログラム間で送受信するデータはプログラミング言語に依存しないため、異なるプログラミング言語で開発したプログラムでも普通に通信を行うことができます。
もしかしたら、Python で HTTP クライアントの開発経験がある方もおられるかもしれませんが、実際にウェブページを表示する際に HTTP クライアントの通信相手となるのは Apache や Nginx (HTTP サーバー) であることが多いです。そして、これらはおそらくC言語で開発されています。つまり、実際に Python で開発した HTTP クライアントを使って HTML の受信等を行ったことがある方は、実は既に “Python で開発したプログラムとC言語で開発したプログラムとの間でソケット通信が可能であること” を体験していることになります。
プログラム間で通信を行うために重要なことは、2つのプログラムが同じプロトコルに従って動作をすることです。もっと簡単に言えば、お互いに息を合わせて通信を行う2つのプログラムを開発することです。これさえ満たせば、異なるプログラミング言語で開発したとしてもプログラム間での通信は成立します。もちろん、このプロトコルは HTTP 等の有名な一般的なものでも問題ないですし、自身で定めた独自のプロトコルでも問題ありません。逆に従うプロトコルが異なっていたり、プロトコルに従わずに開発したような場合は、同じプログラミング言語で開発したとしても通信が成立しません。
ということで、Python で開発したプログラムとC言語で開発したプログラムとでソケット通信を行う場合であっても特別な開発の仕方は不要で、同じプログラミング言語で開発するときと同様に、とにかく同じプロトコルに従うように2つのプログラムを開発すればよいだけです。
あとは、これもプログラミング言語と関係ないですが、受信側が受信待ちしているポート番号に対してデータを送信することや文字のエンコード等を意識することも必要にはなります。
PythonプログラムとC言語プログラム間でのソケット通信
念の為、Python プログラムとC言語プログラムとの間でソケット通信を行うプログラムのサンプルソースコードを紹介しておきます。ここでは、各プログラムが TCP 通信を行うものとし、さらに Python で開発したプログラムがサーバーの位置づけ、C言語で開発したプログラムがクライアントの位置づけになるようにしています。
クライアントとサーバーの間の接続確立後のデータの送受信の流れは、まずクライアントが文字列をサーバーに送信し、さらにサーバーが文字列を大文字に変換した結果をクライアントに返却するだけというシンプルなものになっています。
スポンサーリンク
サーバーのサンプル(Python)
まず Python で作ったサーバーのサンプルソースコードを紹介しておきます。
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('0.0.0.0', 40001))
sock.listen(5)
# 無限ループで常駐させる
while True:
# 接続要求の受付 / 接続の確立
e_sock, addr = sock.accept()
# データの受信待ち
data = e_sock.recv(1024)
# サービス・受信データに応じた処理
str_data = data.decode()
upper_str_data = str_data.upper()
# 処理結果の送信
send_data = upper_str_data.encode()
e_sock.send(send_data)
e_sock.close()
sock.close()
このサーバーは、下記ページの TCP 通信のサーバー で紹介したものと同じです。つまりは、普通に Python で作ったサーバーで、C言語との通信を行うことを意識しなくても、C言語と通信可能なサーバーを作ることができます。
Pythonでのソケット通信(ポート番号・プロトコル・サーバー / クライアント)クライアントのサンプル(C言語)
続いて、C言語で書いた、上記サーバーとの通信相手となるクライアントのサンプルソースコードを紹介します。Linux or Mac 向けのソースコードになっている点に注意してください。Windows だとコンパイルに失敗するはずです。
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define SERVER_ADDR "127.0.0.1"
#define SERVER_PORT 40001
#define BUF_SIZE 1024
int transfer(int);
int transfer(int sock) {
char send_buf[BUF_SIZE], recv_buf[BUF_SIZE];
int send_size, recv_size;
while (1) {
/* サーバーに送る文字列を取得 */
printf("Input Message...\n");
scanf("%s", send_buf);
/* 文字列を送信 */
send_size = send(sock, send_buf, strlen(send_buf) + 1, 0);
if (send_size == -1) {
printf("send error\n");
break;
}
/* サーバーからの応答を受信 */
recv_size = recv(sock, &recv_buf, sizeof(recv_buf), 0);
if (recv_size == -1) {
printf("recv error\n");
break;
}
if (recv_size == 0) {
/* 受信サイズが0の場合は相手が接続閉じていると判断 */
printf("connection ended\n");
break;
}
printf("%s\n", recv_buf);
}
return 0;
}
int main(void) {
int sock;
struct sockaddr_in addr;
/* ソケットを作成 */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
printf("socket error\n");
return -1;
}
/* 構造体を全て0にセット */
memset(&addr, 0, sizeof(struct sockaddr_in));
/* サーバーのIPアドレスとポートの情報を設定 */
addr.sin_family = AF_INET;
addr.sin_port = htons((unsigned short)SERVER_PORT);
addr.sin_addr.s_addr = inet_addr(SERVER_ADDR);
/* サーバーに接続要求送信 */
printf("Start connect...\n");
if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) {
printf("connect error\n");
close(sock);
return -1;
}
printf("Finish connect!\n");
/* 接続済のソケットでデータのやり取り */
transfer(sock);
/* ソケット通信をクローズ */
close(sock);
return 0;
}
こちらは下記ページの クライアントプログラム で紹介したソースコードをベースに変更を加えたものになっています。
【C言語】ソケット通信について解説具体的には、ポート番号の変更(8080
→ 40001
)や受信バッファー(recv_buf
)のサイズや受信したデータの出力の追加等を行っています。これらは別にプログラミング言語の違いによって必要になった変更ではなく、サーバー側の動作に合わせるために加えた変更になります。例えば サーバーのサンプル(Python) で示したサーバーではソケットにバインドするポート番号が 40001
となっているため、それに合わせるためにポート番号を変更していますし、サーバーがレスポンスとして複数バイトのデータを送信してくるため、それを受信できるように recv_buf
のサイズの変更を行っています。
これらの変更からも分かるように、プログラミング言語の違いよりも、サーバーの動きに合わせてクライアントを開発することが重要です。これは、固い言葉で言えば、「お互いに同じプロトコルに従うようにプログラムを開発すること」が重要であるということになります。
また、connect
先の IP アドレスとして 127.0.0.1
を指定しているため、同じ PC 上に存在し、ポート番号 40001
にバインドされたソケットと通信を行うことを前提としたプログラムとなっています。もし、異なる PC 上のプログラムの持つソケットと通信を行いたいのであれば、SERVER_ADDR
の定義値を変更してください。
サンプルの動作確認
最後に動作確認を行い、実際に異なるプログラミング言語で開発したプログラム間でもソケット通信が行えることを確認しておきましょう!ここでは、C言語のコンパイラには gcc
を利用することを前提に解説を進めていきます。
まず、サーバーのサンプル(Python) で示したソースコードを server.py
というファイル名で、さらに クライアントのサンプル(C言語) で示したソースコードを client.c
というファイル名で、それぞれを同じフォルダに保存してください。
そして、ターミナルアプリ(Windows の場合はコマンドプロンプトや PowerShell 等)を2つ起動し、cd
コマンドを実行して両方のターミナルでソースコードを保存したフォルダーに移動してください。
続いて、一方側のターミナルで下記のように server.py
を python
コマンドで実行してください。このターミナルでの操作は以上で終了です。これによりサーバーが立ち上がり、クライアントからのデータの送信を待ち続けるようになります。
python server.py
次に、他方側のターミナルで下記のように client.c
を gcc
コマンドでコンパイルし、実行可能ファイル client.exe
を生成します。
gcc client.c -o client.exe
続いて下記コマンドを実行して、先ほど生成した client.exe
を実行しましょう!すると、まずサーバー(server.py
)との間で接続確立が試みられ、成功すると Finish connect!
が出力されます。続けて文字列の入力が促されますので、適当に小文字で文字列を入力してエンターキーを押してください(scanf
を利用して文字列の入力受付を行っているため、スペースを含まない文字列を入力してください)。
./client.exe Start connect... Finish connect! Input Message...
これにより、入力した文字列を大文字に変換した結果が表示されるはずです。
Input Message... hello_world HELLO_WORLD
この文字列の大文字への変換結果は下記のような流れで出力されたものになります。
- クライアントが文字列をサーバーに送信する
- 受信した文字列をサーバーが大文字に変換する
- サーバーが大文字への変換結果をクライアントに送信する
- 受信した大文字への変換結果をクライアントが出力する
つまり、大文字に変換した結果が出力されているのは、クライアントとサーバーの間での通信が実現できているからになります。したがって、この結果より、クライアントとサーバーの間で通信が行えていること、より詳細に言えば、異なるプログラミング言語で開発したクライアントとサーバーの間で通信が行えていることが確認できたことになります。
今回の場合、クライアント・サーバー間でのソケット通信を実現するために、サーバーに合わせてクライアントを少し変更した点がポイントとなります。このようにサーバーに合わせてクライアントを開発する or クライアントに合わせてサーバーを開発する、固い言葉で言えば、お互いに同じプロトコルに従って動作するようにプログラムを開発してやれば、開発するプログラミング言語にかかわらずソケット通信を行うことは可能です。
以上で、動作確認は終了となります。サーバーもクライアントも無限ループでプログラムが終了しないようになっているため、プログラムを終了させたい場合は control
+ c
を入力して強制終了させてください。
スポンサーリンク
まとめ
このページでは Python プログラムとC言語プログラムとでソケット通信を行うプログラムの作り方について解説しました!
結論としては、特にプログラミング言語の違いを意識しなくてもソケット通信を行うことは可能です。お互いに同じプロトコルに従って動作さえすれば、プログラミング言語の違いに関係なく正常に通信を行うことができます。なので、ソケット通信を行うのであれば、プログラミング言語の違いよりもプロトコルを意識して開発を行うことが重要です。
複数のプログラミング言語でプログラムを開発する場合、お互いのプログラム間でどうやってデータのやりとりをするのかがポイントになることも多いです。そんな時に、そのデータのやりとりをソケット通信を使えば簡単に実現できることは覚えておくと良いと思います!