##開発環境:
####<サーバー側>
・LinuxOS Ubuntu
・VisualStudioCode
####<クライアント側>
・Windows10
・VisualStudio
##はじめに
どうも、はじめましての方は初めまして。ぐっちーです。
サーバーは建てたはいいもののどうやってプログラムとサーバーを通信させたらいいのだろうかネットワーク初心者の私には、全くといいっていいほどわかりませんでした。しかし、先日学校の先生に力を貸していただきなんとかサーバー構築など教えていただけました。
ネットワークがなぜ必要なのか私の目的は何なのか、気になった方もいると思います。.....ただ、ゲームにランキング機能つけたいとかとういう私利私欲です...。
しかーし!WindowsのゲームクライアントとLinuxサーバーでどう通信したらいいの?そもそも関数の使用法がちがってくるの?という疑問にぶち当たりました。なので調べたものをここに書き記します。
使用するのはSocket通信!これを使ってざっくり解説していきます!
##①インクルードやら定数宣言
###【Windows】
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <string>
// 接続先
#define SEVER_IP_ADDRESSE "127.0.0.1"
#define SERVER_PORT 12345
// バッファ
#define BUFSIZE 256
#define RECVSIZE 65536
【Linux】
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <memory.h>
#define SERVER_PORT 11110
#define BUFSIZE 256
うわー全然違うじゃん....。
Linuxはやっぱりカスタマイズ向けだけありますね...(笑)
ちなみに、今回ここに記述してあるのはローカルホスト向けです。
もしグローバルでネットを介して通信したい方は、ポート開放して、クライアント側のSERVER_PORTに入れてあげましょう。SEVER_IP_ADDRESSEにはグローバルIPをいれてあげればできます。
##②変数とか最初の処理とかソケット生成
###【Windows】
// セットアップ
WSADATA wsaDate;
// サーバー情報
SOCKADDR_IN server;
// 初期化
WSAStartup(MAKEWORD(2, 0), &wsaDate);
// ソケット生成
int soc;
char sendBuf[BUFSIZE];
char recvBuf[RECVSIZE];
int recvLen = 0;
soc = socket(AF_INET, SOCK_STREAM, 0);
【Linux】
// 接続先情報
socklen_t len = sizeof(struct sockaddr_in);
struct sockaddr_in from_addr;
// バッファ
char buf[BUFSIZE];
// 受信バッファ初期化
memset(buf,0,sizeof(buf));
// ソケット生成
int socfd;
int client_soc;
struct sockaddr_in addr;
socfd = socket(AF_INET,SOCK_STREAM,0)
似たようなところがたくさなりますね...。ただ、気を付けてほしいのはWinSocketを使用する場合は絶対スタートアップをしなければなりません!初期化ですね。
・MAKEWORD(2, 0) ・・・ winsocのバージョンの指定です。1.0と2.0があるので今回は2.0を使用しました。
・AF_INIT ・・・ ソケットドメイン(Webのドメインではありません)プロトコルらしいです。とりあえずこれを指定しとけば大丈夫
・SOCK_STREAM ・・・ TCP接続でできるみたいです。ほかにも、SOCK_DGRAMを指定すると、UDP接続できるらしいです。
##③サーバーアドレス情報いれていく
###【Windows】
// サーバーのアドレス情報
server.sin_family = AF_INET; // アドレスファミリ
server.sin_port = htons(SERVER_PORT); // ポート
server.sin_addr.S_un.S_addr = inet_addr(SEVER_IP_ADDRESSE); // IPアドレス
【Linux】
// 待ち受け用のアドレス情報
addr.sin_family = AF_INET; // アドレスファミリ
addr.sin_port = htons(SERVER_PORT); // ポート
addr.sin_addr.s_addr = INADDR_ANY; // 接続を許可するIPアドレス
なにか新しいものがたくさんでてきましたね。初心者の方はぱっと見ナニコレおいしいの?状態ですね(笑)
ざっくり説明していきましょう。
・htons ・・・ バイトオーダーというものです。ネットワーク用に使うためには変化しないといけないようで、その文字を変換する関数のようです。簡潔に言うとネットワーク用に変換する関数です。
・inet_addr ・・・ これも、IPアドレスをネットワークで使える形に変換する関数です。
・INADDR_ANY ・・・ 全てのIPからの接続を許可するらしいです。
##④バインドする
【Linux】
bind(socfd,(struct sockaddr *)&addr,sizeof(addr)
##⑤クライアントからの接続を待つ
【Linux】
listen(socfd,SOMAXCONN)
・SOMAXCONN ・・・ 接続を待機させる最大数です。
##⑥サーバーに接続
###【Windows】
connect(soc, (LPSOCKADDR)&server, sizeof(server));
##⑦サーバーに送信
send(soc, sendText.c_str(), sendText.size(), 0)
##⑧サーバーから受信
###【Windows】
recv(soc, recvBuf, RECVSIZE, 0);
##⑨クライアントに送信
【Linux】
write(client_soc , buf , strlen(buf));
##⑩クライアントから受信
【Linux】
read(client_soc ,buf , sizeof(buf)
##⑪終了処理
###【Windows】
// 終了
closesocket(soc);
WSACleanup();
【Linux】
//終了
close(client_soc);
close(socfd);
処理の最後とエラーチェックには必ずがソケットを閉じましょう!
Winsocの場合はStartUp()をしているので、必ずWSACleanup()で閉じてあげましょう。
##最期に
GitHubに今回の処理を使って、クライアントから文字を入力してサーバーへ送信し、サーバーファイルをテキストとして保存してくれる簡単なソースコードを載せました。参考までにどうぞ!
URL:https://github.com/HiguchiRyuya/Socket_LixS_WinC
#☆思ったこと
うん...。次はWeb経由でCからPHPでGETして、MySQLを叩いてもらってくるようにしたほうが簡単だったので挑戦してみます。
参考
・学校の先生
・http://www.geocities.jp/playtown1056/program/ws_6.htm
・http://www.geekpage.jp/programming/linux-network/