ページ 1 / 1
UDP通信について
Posted: 2013年8月11日(日) 07:58
by こっこ
現在windows8 でUDPの通信プログラムを書いているのですが受信部、送信部をそれぞれ関数にしたらコンパイルエラーが出てしみました。
buf は文字が入るのでポインタを使ったほうが処理が速いのでポインタを使いたいのですがどのようにすればうまくできるでしょうか。
コード:
#include <stdio.h>
#include <winsock2.h>
#pragma once
#pragma comment(lib,"ws2_32.lib")
bool setup();
bool network_read(char);
bool network_send();
bool end();
WSAData wsaData;
SOCKET sock;
struct sockaddr_in addr;
void main(){
//受信データ
char buf[2048];
///設定
setup();
while(1){
///データ受信
network_read(*buf);
///データ送信
network_send();
}
///終了処理
end();
}
bool network_send(){
sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));
return 0;
}
bool network_read(char *buf){
memset(buf, 0, sizeof(buf));
recv(sock, buf, sizeof(buf), 0);
return 0;
}
bool setup(){
WSAStartup(MAKEWORD(2,0), &wsaData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
return 0;
}
bool end(){
closesocket(sock);
WSACleanup();
return 0;
}
Re: UDP通信について
Posted: 2013年8月11日(日) 08:10
by h2so5
27行目でポインタ型の引数に間接参照を渡しているのがコンパイルエラーの原因だと思います。
Re: UDP通信について
Posted: 2013年8月11日(日) 09:45
by non
43行目sizeofも問題ありそうです。
Re: UDP通信について
Posted: 2013年8月11日(日) 18:14
by こっこ
27行目だけ直しました。
43行目はよくわかりません。
下記のようなエラーが出ます。
エラー 1 error C2664: 'network_read' : 1 番目の引数を 'char [2048]' から 'char' に変換できません。(新しい機能 ; ヘルプを参照)
VC2012EX
コード:
#include <stdio.h>
#include <winsock2.h>
#pragma once
#pragma comment(lib,"ws2_32.lib")
bool setup();
bool network_read(char);
bool network_send();
bool end();
WSAData wsaData;
SOCKET sock;
struct sockaddr_in addr;
void main(){
//受信データ
char buf[2048];
///設定
setup();
while(1){
///データ受信
network_read(buf);
///データ送信
network_send();
}
///終了処理
end();
}
bool network_send(){
sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));
return 0;
}
bool network_read(char *buf){
memset(buf, 0, sizeof(buf));
recv(sock, buf, sizeof(buf), 0);
return 0;
}
bool setup(){
WSAStartup(MAKEWORD(2,0), &wsaData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
return 0;
}
bool end(){
closesocket(sock);
WSACleanup();
return 0;
}
Re: UDP通信について
Posted: 2013年8月11日(日) 18:52
by softya(ソフト屋)
まずエラーですが、
bool network_read(char);
と
bool network_read(char *buf){
で型が違うのが原因です。
この間違いで不安になるのは、ポインタの扱いや文字列の理解が不十分じゃないかと言うことです。
それとchar *bufは文字列バッファを渡せてもサイズは渡せませんので、sizeof(buf)はポインタのサイズとなり望んだ動作はしません。
サイズも引数にする必要があります。
コード:
bool network_read(char *buf){
memset(buf, 0, sizeof(buf));
recv(sock, buf, sizeof(buf), 0);
return 0;
}
Re: UDP通信について
Posted: 2013年8月11日(日) 19:14
by こっこ
プロトタイプ宣言ですが、ポインタという型であることを忘れていました。
bool network_read(char *);
http://www7b.biglobe.ne.jp/~robe/cpphtm ... 01057.html
でポインタからサイズを取得することはできないことがよくわかりました。
これでいいでしょうか。
コード:
#include <stdio.h>
#include <winsock2.h>
#pragma once
#pragma comment(lib,"ws2_32.lib")
bool setup();
bool network_read(char *,int);
bool network_send();
bool end();
WSAData wsaData;
SOCKET sock;
struct sockaddr_in addr;
void main(){
//受信データ
char buf[2048];
///設定
setup();
while(1){
///データ受信
network_read(buf,sizeof(buf));
///データ送信
network_send();
}
///終了処理
end();
}
bool network_send(){
sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));
return 0;
}
bool network_read(char *buf ,int size){
memset(buf, 0, size);
recv(sock, buf, size, 0);
return 0;
}
bool setup(){
WSAStartup(MAKEWORD(2,0), &wsaData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
return 0;
}
bool end(){
closesocket(sock);
WSACleanup();
return 0;
}
Re: UDP通信について
Posted: 2013年8月11日(日) 19:16
by softya(ソフト屋)
プロトタイプをまた間違っているので、エラーになると思いますよ。
コンパイルしてから投稿してくださいね。
ごめんなさい勘違いでした。
Re: UDP通信について
Posted: 2013年8月11日(日) 19:19
by softya(ソフト屋)
気を取り直して、不安なのは、recv(sock, buf, size, 0);で2048バイトぴっちり受信した場合に文字列終端がない場合がありえると言うことぐらいでしょうか。
あとは大丈夫だと思います。
Re: UDP通信について
Posted: 2013年8月11日(日) 19:29
by こっこ
EOFがないこと自体は受信には何の問題もないが、そのあとの処理に注意するべきである。ということでいいでしょうか。
Re: UDP通信について
Posted: 2013年8月11日(日) 19:50
by softya(ソフト屋)
EOFではなく文字列終端は0x00です。これはいくら注意しても誤動作するのでバッファギリギリまで受信するすのは避けるべきです。
Re: UDP通信について
Posted: 2013年8月11日(日) 20:07
by こっこ
ありがとうございました。
最後に載せたソースコードが最終形です。
Re: UDP通信について
Posted: 2013年8月11日(日) 20:08
by softya(ソフト屋)
文字列を2048バイト受信すると、たぶん落ちるのでこれで良かったんでしょうか?
Re: UDP通信について
Posted: 2013年8月11日(日) 22:03
by こっこ
??
受信には何も問題がなかったのでは。
やっぱり問題があるのですね。
http://chokuto.ifdef.jp/advanced/function/recv.html
で調べた結果切捨てされるだけなので問題ないと思っています。
勝手にプログラムが終了するわけではないと思っていますがこれは正しいでしょうか。
Re: UDP通信について
Posted: 2013年8月11日(日) 22:08
by みけCAT
このコードには、受信したデータを出力する部分は無いようです。
Re: UDP通信について
Posted: 2013年8月11日(日) 22:33
by softya(ソフト屋)
No.8から書いている通り文字列終端の処理が考慮されていません。
この提示コードの範囲内では動作しますが、2048文字送ってしまった場合の動作は保証出来ません。
※ 現在のsendto()は5文字固定ですから。
>勝手にプログラムが終了するわけではないと思っていますがこれは正しいでしょうか。
たぶん、2048文字送ると異常終了するか、しないかもしれませんが2048文字以降が化けた文字列になると思います。
偶然無事な可能性もありますが常に無事な保証はできません。
[補足]
このコードの正常性は、受信した文字列の表示がない&5文字しか送っていないと言う限定条件の正常動作と言うことです。
Re: UDP通信について
Posted: 2013年8月12日(月) 00:34
by Poco
まだ見ていることを祈りつつ。
UDPの場合、受信のためのAPIはrecv()ではなく、recvfrom()です。
Re: UDP通信について
Posted: 2013年8月12日(月) 06:53
by こっこ
どうですか。
エラー処理をつけてみました。
コード:
#include <stdio.h>
#include <winsock2.h>
#pragma once
#pragma comment(lib,"ws2_32.lib")
bool setup();
bool network_read(char *,int);
bool network_send();
bool end();
WSAData wsaData;
SOCKET sock;
struct sockaddr_in addr;
void main(){
//受信データ
char buf[2048];
///設定
setup();
while(1){
///データ受信
network_read(buf,sizeof(buf));
///データ送信
network_send();
}
///終了処理
end();
}
bool network_send(){
sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));
return 0;
}
bool network_read(char *buf ,int size){
memset(buf, 0, size);
if(recv(sock, buf, size, 0) == -1){
return 0;
}
return 1;
}
bool setup(){
WSAStartup(MAKEWORD(2,0), &wsaData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
return 0;
}
bool end(){
closesocket(sock);
WSACleanup();
return 0;
}
Re: UDP通信について
Posted: 2013年8月12日(月) 11:00
by softya(ソフト屋)
Pocoさんのが反映されてませんね。
それとrecv()のエラーにはならないので、自分で受信長を知らべてエラー処理なり、2047バイトに収まるようにするなり工夫してください。
[補足] あれ? Winsock2だとrecvform()じゃなくてrecv()でOKなのか? 調べてきます。
【補足追記】 bindしてないのでrecv()だと不可ですね。
Re: UDP通信について
Posted: 2013年8月16日(金) 12:23
by こっこ
遅くなりました。
いろいろ付け加えてみました。
ここでまたいくつかの問題が発生しました。
受信を待つようなブロッキングモードにしておくとプログラムが止まってしまうのでノンブロッキングモードのしたのですがCPUの使用率が半端ないです。
解決方法としてはマルチスレッド等があるようですが全くわかりません。
どうしたらCPUの使用率を下げることができますか。
コード:
#include <stdio.h>
#include <winsock2.h>
#pragma once
#pragma comment(lib,"ws2_32.lib")
bool setup();
bool network_read(char *,int);
bool network_send();
bool end();
WSAData wsaData;
SOCKET sock;
struct sockaddr_in addr;
void main(){
//受信データ
char buf[2048];
///設定
WSAStartup(MAKEWORD(2,0), &wsaData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
// ここで、ノンブロッキングに設定しています。
u_long val=1;
ioctlsocket(sock, FIONBIO, &val);
while(1){
///データ受信
network_read(buf,sizeof(buf));
///データ送信
network_send();
}
///終了処理
closesocket(sock);
WSACleanup();
}
bool network_send(){
addr.sin_port = htons(宛先ポート);
addr.sin_addr.S_un.S_addr = inet_addr("宛先IP");
sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));
return 0;
}
bool network_read(char *buf ,int size){
memset(buf, 0, size);
if(recv(sock, buf, size, 0) == -1){
return 0;
}
return 1;
}
Re: UDP通信について
Posted: 2013年8月16日(金) 12:29
by みけCAT
while(1)のループ内にSleep(10);を入れるとCPU使用率は下がると思います。
Re: UDP通信について
Posted: 2013年8月16日(金) 12:57
by こっこ
ありがとうございます。
whileの一番下に入れても受信に失敗したらcontinueされるのでwhileの直後に入れることにしました。
コード:
#include <stdio.h>
#include <winsock2.h>
#pragma once
#pragma comment(lib,"ws2_32.lib")
bool setup();
bool network_read(char *,int);
bool network_send();
bool end();
WSAData wsaData;
SOCKET sock;
struct sockaddr_in addr;
void main(){
//受信データ
char buf[2048];
///設定
WSAStartup(MAKEWORD(2,0), &wsaData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
// ここで、ノンブロッキングに設定しています。
u_long val=1;
ioctlsocket(sock, FIONBIO, &val);
while(1){
///データ受信
network_read(buf,sizeof(buf));
///データ送信
network_send();
}
///終了処理
closesocket(sock);
WSACleanup();
}
bool network_send(){
addr.sin_port = htons(宛先ポート);
addr.sin_addr.S_un.S_addr = inet_addr("宛先IP");
sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));
return 0;
}
bool network_read(char *buf ,int size){
memset(buf, 0, size);
if(recv(sock, buf, size, 0) == -1){
return 0;
}
return 1;
}
Re: UDP通信について
Posted: 2013年8月16日(金) 14:48
by みけCAT
こっこ さんが書きました:whileの一番下に入れても受信に失敗したらcontinueされるのでwhileの直後に入れることにしました。
ごめんなさい。
提示されたコードには1箇所しかwhileが見えず、
そこではcontinueしている様子も無ければSleepしている様子も無いのですが、
どういう意味ですか?
オフトピック
こっこ さんが書きました:解決方法としてはマルチスレッド等があるようですが全くわかりません。
マルチスレッドにしたら余計にCPU使用率が上がるかもしれません。(OpenMP等)