📦
Socket通信 (Windows C++/C#)
やりたかったこと
他のアプリとのプロセス間通信をしたくて、socket通信を使ってみた。
送信側がC++、受信側がC#です。
やり方
やり方はいろんなサイトに紹介されてます。
C#での受信の一例は下記のとおり。
IPAddress host1 = IPAddress.Parse("127.0.0.1");
int port1 = 12345;
IPEndPoint ipe1 = new IPEndPoint(host1, port1);
TcpListener server = null;
byte[] buf = new byte[SentDataLength];
server = new TcpListener(ipe1);
server.Start();
int count = 0;
while(count < 10)
{
using (var client = server.AcceptTcpClient()){
using (var stream = client.GetStream()){
while ((stream.Read(buf, 0, buf.Length)) == buf.Length){
// 受信したものへの処理
}
}
}
count++;
}
server.Stop();
C++での送信の一例が下記のとおり。
WSADATA wsa_data;
sockaddr_in addr;
WSAStartup(MAKEWORD(2, 0), &wsa_data)
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
int port1 = 12345;
std::string address1 = "127.0.0.1";
addr.sin_port = htons(port1);
inet_pton(addr.sin_family, address1.c_str(), &addr.sin_addr.s_addr);
int socket1 = socket(AF_INET, SOCK_STREAM, 0);
connect(socket1, (struct sockaddr*)&addr, sizeof(addr));
char* cdata = new char[send_length];
// cdataの値を設定するなにかしらの処理(省略)
send(socket1, cdata, send_length, 0);
closesocket(socket1);
delete [] cdata;
// 終了処理
WSACleanup();
つまったところ
socket関連の謎のエラー
エラー内容:
'sockaddr': 'struct'型の再定義
構文エラー:'}'が'定数'の前にありません。
・・・
↑まったく心あたりのない大量のエラー。
対処方法:
winsock2.h
のインクルードがwindows.h
より前になるように修正
windows.hとのインクルード順のエラーは本当に多い。。。
ライブラリ追加忘れ
エラー内容:
外部シンボル__imp_htonsは未解決です
外部シンボル__imp_connectは未解決です
外部シンボル__imp_socketは未解決です
外部シンボル__imp_sendは未解決です
・・・
対処方法:
ws2_32.lib
を追加の依存ファイルに追加
char配列ではなくshort配列を受け渡ししたい
いろんなサイトに紹介してあるのは、スタンダードなchar配列の送受信です。
簡単なIFの関数がないのか探したのですが見つからず。今回short型を送るにあたり、どうやら自分で素直にchar型(byte型)に変換するしかなさそう。
下記は送る側のC++コード。
char* cdata = new char[send_length];
int num = 0;
for(int i = 0; i < N; i++)
{
short sdata = (short)data[i];
cdata[num] = (char)(sdata & 0xff);
cdata[num + 1] = (char)((sdata >> 8) & 0xff);
num += 2;
}
// 送る
send(dst_socket, cdata, send_length, 0);
下記が受け取る側のC#コード。
while ((stream.Read(buf, 0, buf.Length) == buf.Length)
{
for(int i = 0; i < N; i++)
{
short d1 = buf[i * 2];
short d2 = buf[i * 2 + 1];
short sData = (short)(d1 | (short)(d2 << 8));
data[i] = sData;
}
}
動かない問題 server.AcceptTcpClient()
server = new TcpListener(ipe1);
server.Start();
while(!stopApp)
{
using (var client = server.AcceptTcpClient()){
using (var stream = client.GetStream()){
while ((stream.Read(buf, 0, buf.Length)) == buf.Length){
// 受信したものへの処理
}
}
}
await Task.Delay(1000);
}
server.Stop();
上記のような受信側のコードを書いたとき、client側が送信のための接続をしてくれない場合、接続が確立せず、ずっとserver.AcceptTcpClient()
で待ち続けるということが起こりました。
当初の予定ではエラーが起きてcatchのとこでTimeoutのようなエラーを処理するようにすればいいかと思っていたのですが、エラーなしで、待ち続ける仕様でした。
というわけで、調べると、タイムアウトを設定できるらしい。上のほうの2行に下記を追加。1秒だけ待ちます。
server = new TcpListener(ipe1);
Socket serverSocket = server.Server;
LingerOption lingerOption = new LingerOption(true, 1); // 1秒待つ
serverSocket.SetSocketOption(
SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption);
server.Start();
これで、動かない問題は解消しました。
下記が参考にしたサイトです。
Discussion