• 締切済み

getaddrinf()で取得したIPアドレス表示

お世話になります。 C言語でソケット通信の勉強中です。 CentOS6.4を使っています。 LIST1は、 IPアドレスではなくホスト名がコマンド引数で渡されたとき、 getaddrinfo()でIPアドレスを取得して、 sendto()でサーバにメッセージを送信するだけの、 クライアントのプログラムです。 このLIST1のudp通信自体は上手くいくのですが、 終わりの方で、 getaddrinfo()で取得したIPアドレスを inet_ntoa()を使って文字列表示しようとすると、 セグメンテーション違反です (コアダンプ)となってしまいます。 inet_ntoa()の引数が疑わしく、 いろいろ渡し方を変えたり、参照方法を変えたりしてみたのですが、、 なかなか解決しません。 ちゃんと、192.168.12.1とか表示するにはどうすれば良いでしょうか? ■LIST1 #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <errno.h> int main(int argc,char *argv[]){ int sock; struct addrinfo hints,*res; int n; int err; if(argc != 2){ fprintf(stderr,"Usage : %s dst \n",argv[0]); return 1; } /* IP アドレス表記+ホスト名両方に対応 */ memset(&hints,0,sizeof(hints)); hints.ai_family = AF_UNSPEC; /* IPV4 IPV6 両方に対応 */ hints.ai_socktype = SOCK_DGRAM; err = getaddrinfo(argv[1],"12345",&hints,&res); if(err != 0){ perror("getaddrinfo"); printf("getaddrinfo %s\n",strerror(errno)); printf("getaddrinfo : %s \n",gai_strerror(err)); return 1; } sock = socket(res->ai_family,res->ai_socktype,0); if(sock < 0){ perror("socket"); return 1; } { const char *ipverstr; switch (res->ai_family){ case AF_INET: ipverstr = "IPv4"; break; case AF_INET6: ipverstr = "IPv6"; break; default: ipverstr = "unknown"; break; } printf("ipverstr = %s\n ",ipverstr); } n = sendto(sock,"HELLO",5,0,res->ai_addr,res->ai_addrlen); //n = sendto(sock,"HELLO", 5, 0,(struct sockaddr *)addr, sizeof(addr)); if(n<1){ perror("sendto"); { } return 1; } printf("############ finish !! #######\n"); close(sock); freeaddrinfo(res); struct sockaddr_in *addr; addr = (struct sockaddr_in *)res->ai_addr; printf("inet_ntoa(in_addr)sin = %s\n",inet_ntoa((struct in_addr)addr->sin_addr)); return 0; }

みんなの回答

回答No.1

典型的なuse after freeに見えますが? > freeaddrinfo(res); でresを開放して、 > struct sockaddr_in *addr; > addr = (struct sockaddr_in *)res->ai_addr; と、開放した値を参照しているようですが? freeaddrinfoしたらその中のすべての値は解放されますよね。

freeradical
質問者

お礼

ご回答ありがとうございます。

freeradical
質問者

補足

大変申し訳ありません。 LIST1として掲載するソースのバージョンを間違えていました。freeaddrinfo()よりも前、"###finish !!###"の直前で実施しているものがあり、そちらでもセグメンテーション違反となってしまいます。 よろしくお願いします。

関連するQ&A

  • UDPでのブロードキャスト送信

    Linuxで下記UDPブロードキャスト送信プログラムを作ったのですが、sendto()関数の戻り値が-1となり エラーとなってしまうので送信できません。 何が悪いのでしょうか? ちなみにIPアドレスは192.168.0.1 サブネットマスクは255.255.0..0でやっています。 又、サブネットマスクを0.0.0.0で試してもみましたがダメでした。 #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> int main() { int sock; struct sockaddr_in addr; int yes = 1; sock = socket(AF_INET, SOCK_DGRAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(12345); addr.sin_addr.s_addr = inet_addr("255.255.255.255"); setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&yes, sizeof(yes)); if(sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr))!=5) printf("send error!!\n"); close(sock); return 0; }

  • C言語ソケットでWikipediaの情報入手

    以下のCコードで > gcc wiki_client.c -o wiki_client > ./wiki_client "O'Reilly_Media" として https://en.wikipedia.org/wiki/O%27Reilly_Media の情報を得ようとしているのですが、 HTTP/1.1 400 Bad Request が返ってきます。 これは本に載っていたままのコードなのですが、 どこをどう直せばいいのか分かりません。 どこを直せばいいか教えて下さい。 ブラウザからはもちろんアクセスできます。 環境はUbuntu 18.04のgcc 7.3.0です。 ではよろしくお願いします。 // wiki_client.c #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <netdb.h> void error(char *msg) { fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(1); } int open_socket(char *host, char *port) { struct addrinfo *res; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(host, port, &hints, &res) == -1) error("Can't resolve the address"); int d_sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (d_sock == -1) error("Can't open socket"); int c = connect(d_sock, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); if (c == -1) error("Can't connect to socket"); return d_sock; } int say(int socket, char *s) { int result = send(socket, s, strlen(s), 0); if (result == -1) fprintf(stderr, "%s: %s\n", "Error talking to the server", strerror(errno)); return result; } int main(int argc, char *argv[]) { int d_sock; d_sock = open_socket("en.wikipedia.org", "80"); char buf[255]; sprintf(buf, "GET /wiki/%s http/1.1\r\n", argv[1]); say(d_sock, buf); say(d_sock, "Host: en.wikipedia.org\r\n\r\n"); char rec[256]; int bytesRcvd = recv(d_sock, rec, 255, 0); while (bytesRcvd) { if (bytesRcvd == -1) error("Can't read from server"); rec[bytesRcvd] = '\0'; printf("%s", rec); bytesRcvd = recv(d_sock, rec, 255, 0); } close(d_sock); return 0; }

  • icmpv6(ping6)の応答を受信できない

    ipv6、ipv4のpingの送受信ができる、ipv4ipv6pingexampleと言うソースをダウンロードし実行したのですが、ipv6の受信のみが出来ません。 スニファーソフトで見ると、ping6の応答は帰っているが、受信(WSARecvFrom)でタイムアウトとなる。 確認のため、icmpv6(ping6)の応答を受信する部分のみ作成してテストしても、同様になります。 受信ソケットのbindの引数のaddrinfoに原因があるのではと試しましたがうまくいきません。 アドバイスをお願いいたします。 環境 windowsXP(SP3)、VC++2008 ping先は家のルータ、DOSウィンドウからping6を入力 ipv4は受信できる。スニファーソフトで見ると、ping6の応答は帰っている。 以下は確認用のコード #include <stdio.h> #include "winsock2.h" #include <ws2tcpip.h> #include "iphdrv2.h" #pragma comment(lib, "ws2_32.lib") void main() { WSADATA wsaData; SOCKET RecvSocket; char RecvBuf[1024]; int BufLen = 1024; SOCKADDR_STORAGE from; int fromsize = sizeof(from); struct addrinfo hints, *local=NULL; int rc; // for ipv4 //int af = PF_INET, type = SOCK_RAW, proto = IPPROTO_ICMP; // for ipv6 int af = PF_INET6, type = SOCK_RAW, proto = IPPROTO_ICMPV6; // Winsock を初期化します。 WSAStartup(MAKEWORD(2,2), &wsaData); // データ受信用のソケットを作成します。 RecvSocket = socket(af, type, proto); // struct addrinfo { * // int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ // int ai_family; /* PF_xxx */ // int ai_socktype; /* SOCK_xxx */ // int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ // size_t ai_addrlen; /* length of ai_addr */ // char *ai_canonname; /* canonical name for nodename */ // struct sockaddr *ai_addr; /* binary address */ // struct addrinfo *ai_next; /* next structure in linked list */ // }; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = af; hints.ai_socktype = type; hints.ai_protocol = proto; //rc = getaddrinfo(addr, port, &hints, &res); rc = getaddrinfo(NULL, "0", &hints, &local); if (rc != 0) { printf("getaddrinfo() failed with error code %d\n", rc); printf("Unable to obtain the bind address! with error code %d\n", WSAGetLastError()); getchar(); return ; } //bind rc = bind(RecvSocket, local->ai_addr, local->ai_addrlen); if (rc == SOCKET_ERROR) { fprintf(stderr, "bind() failed with error code %d\n", WSAGetLastError()); getchar(); return ; } // データを受信します。 printf("データの受信中……\n"); rc =recvfrom(RecvSocket,RecvBuf,BufLen,0,(SOCKADDR *)&from,&fromsize); //rc =recv(RecvSocket,RecvBuf,BufLen, 0); if(rc == -1){ printf("Recv failed with error code %d\n", WSAGetLastError()); } else { printf("受信が完了しました。%d Byte\n",rc); } closesocket(RecvSocket); printf("終了します。\n"); freeaddrinfo(local); WSACleanup(); return; }

  • Cプログラム UDP送信の送信データに関して

    以下の2つのプログラムでの質問なのですが、 #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") int main() { WSADATA wsaData; SOCKET sock; struct sockaddr_in addr; WSAStartup(MAKEWORD(2, 0), &wsaData); sock = socket(AF_INET, SOCK_DGRAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(3054); addr.sin_addr.S_un.S_addr = inet_addr("192.168.0.3 "); sendto(sock, "\x42\42\0\0\0\0\2\0\1\2\x44\x33\5", 13, 0, (struct sockaddr *)&addr, sizeof(addr)); closesocket(sock); WSACleanup(); return 0; } と #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") int main() { WSADATA wsaData; SOCKET sock; struct sockaddr_in addr; WSAStartup(MAKEWORD(2, 0), &wsaData); sock = socket(AF_INET, SOCK_DGRAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(3054); addr.sin_addr.S_un.S_addr = inet_addr("192.168.0.3 "); sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr)); closesocket(sock); WSACleanup(); return 0; } について、送信データ部分に「¥」入ることによって、送信プロセスでどのような処理がなされているのですか? ¥~¥までで1バイトということで処理してくださいね、と処理系?に指示しているのですか? また、「¥」はC言語ならではの表記の仕方なのですか?少し、伝えるのが難しいですが、何でもいいのでご回答頂けませんか?宜しくお願いします。

  • IPアドレスを配列に代入する方法。

    パケットモニタリング(tcpdumpみたいなもの)でIPアドレスを取得するプログラムがあるのですが、IPアドレスを配列に代入することが出来ません。 パケットモニタリングのソース void print_ip(struct ip *ip) { printf("| Source IP Address: %15s|\n", inet_ntoa(*(struct in_addr *) &(ip->ip_src))); /* ループ */ 実行画面 | Source IP Address: 12.34.56.78 | | Source IP Address: 34.56.78.09 | ・ ・ というふうにどんどん取得、表示していく このIPアドレス inet_ntoa(*(struct in_addr *) &(ip->ip_src))); を配列に代入していきたいのですが上手くいきません。一応自分でやってみたのですが、 void print_ip(struct ip *ip) { int *pa[2048]; static int i = 1; printf("| Source IP Address: %15s|\n", inet_ntoa(*(struct in_addr *) &(ip->ip_src))); i++; pa[i] = (int *)&(ip->ip_src); printf("送信先[%d]%15s\n", i, inet_ntoa(*(struct in_addr *) pa[i])); if (i == 10) { for (i = 1; i < 10; i++) { printf("送信先[%d]%15s\n", i, inet_ntoa(*(struct in_addr *) pa[i])); }} } という風にaddres[1]から順にどんどんIPアドレスを格納しようとしたんですがaddres[1]からaddres[10]まで表示するときに全部addres[10]に代入されているIPアドレスが表示されてしまいます。 おそらく配列にIPアドレスが上手く格納できてないんだと思うのですが。C言語初心者なので誰かご教授していただけないでしょうか? 宜しくお願いします。 OSはLinuxです。

  • winsockを使った通信方法

    送信側 #include <winsock2.h> #include <string.h> int main() { WSAData wsaData; SOCKET sock; struct sockaddr_in addr; int len; typedef struct recv { char Name[32]; int Flag; } RECV; RECV send; 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"); strcat(send.Name, "ABC"); send.Flag=12; len=sizeof(send); sendto(sock,(char *)&send,len, 0, (struct sockaddr *)&addr, sizeof(addr)); closesocket(sock); WSACleanup(); system("pause"); return 0; } 受信側 #include <stdio.h> #include <winsock2.h> #include <string.h> int main() { typedef struct rcv { char Name[32]; int Flag; } RECV; WSAData wsaData; SOCKET sock; struct sockaddr_in addr; int len; RECV rcv; 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 = INADDR_ANY; bind(sock, (struct sockaddr *)&addr, sizeof(addr)); len=sizeof(rcv); recv(sock,(char *)&rcv, len, 0); printf("%s [%d]\n",rcv.Name,rcv.Flag); closesocket(sock); WSACleanup(); system("pause"); return 0; } winsockを使ったUDP通信プログラムで構造体データを送る事が出来ないのですが どこに誤りがあるのでしょうか? コンパイルは通ってるのですが、送信側を起動しても受信側で受け取ることが出来ていない状況です。

  • C言語開発環境について

    このプログラムを実行出来るコンパイラ?あるいは開発環境を紹介して頂けませんか?出来れば無償版がいいです。よろしくお願い致します。 #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") int main() { WSAData wsaData; SOCKET sock; struct sockaddr_in addr; WSAStartup(MAKEWORD(2,0), &wsaData); sock = socket(AF_INET, SOCK_DGRAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(3054); addr.sin_addr.S_un.S_addr = inet_addr("192.168.0.3"); sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr)); closesocket(sock); WSACleanup(); return 0; }

  • アドレスの比較について

    こんにちは。質問させてもらいます。 pcap.hを使って、取得したパケットの送信元アドレスと送信先アドレスを比較させて、違うアドか同じアドかを判断したいと考えています。 しかし、送信元アドレスと送信先アドレスが明らかに違うのに、同一だと判断してしまいます。原因を教えてもらえないでしょうか。 ipアドレスを格納する構造体は struct ip { struct in_addr ip_src, ip_dst; }; としました。 ↓が試した方法です。 1.inet_ntoaの値をそのまま比較 if ( inet_ntoa(ip->ip_src) == inet_ntoa(ip->ip_dst) ) { printf("\nアドレスいっしょ\n"); //↓はアドレスが違っているかどうか確認 printf("src:%s\n",inet_ntoa(ip->ip_src)); printf("dst:%s\n",inet_ntoa(ip->ip_dst)); } else { printf("\nアドレス違う\n"); } 2.strcmpを使う if ( strcmp(inet_ntoa(ip->ip_src),inet_ntoa(ip->ip_dst)) == 0) { printf("\nアドレスいっしょ\n"); printf("src:%s\n",inet_ntoa(ip->ip_src)); printf("dst:%s\n",inet_ntoa(ip->ip_dst)); } else { printf("\nアドレス違う\n"); } どちらでやってもアドレスは同じと判断してしまいます。printfで確認するときっちり違うアドが表示されるのに・・何故? きちんとアドレスを比較してくれるようにif文の中身を変えたいです。 ご助力お願いできますか。

  • C言語エラーの解決法教えてください。

    以下のプログラムで6行目にこのようなエラー表示がでてきたのですが、どうすれば良いですか? 1 IntelliSense: 識別子 "WSAData" が定義されていません 2 IntelliSense: 識別子 "wsaData" が定義されていません #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") int main() { WSAData; wsaData; SOCKET sock; struct sockaddr_in addr; WSAStartup(MAKEWORD(2,0), &wsaData); sock = socket(AF_INET, SOCK_DGRAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(9750); addr.sin_addr.S_un.S_addr = inet_addr("192.168.0.8 "); sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr)); closesocket(sock); WSACleanup(); return 0; } 教えてください。宜しくお願いします。

  • 外部シンボルって

    本に載っていた以下のようなサンプルコード #include <stdio.h> #include <winsock.h> void main( void ) { WSADATA wsadata; if ( WSAStartup( 0x0101, &wsadata ) != 0 ) { printf( "WSAStartup の実行に失敗 %d\n", WSAGetLastError()); } int sock; struct sockaddr_in addr; int ret ; struct hostent *hostinfo; unsigned long inetaddress; char *hostname = "localhost"; inetaddress = inet_addr( hostname ); if ( inetaddress == INADDR_NONE ) { hostinfo = gethostbyname( hostname ); if ( hostinfo == 0 ) { // ホスト名解決に失敗 return ; } inetaddress = *(unsigned long *)hostinfo->h_addr_list[0]; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = inetaddress; addr.sin_port = htons(80); sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); ret = connect( sock, (struct sockaddr *)&addr, sizeof addr ); if ( ret < 0 ) { printf( "localhost 80 に接続できなかった" ); return ; } char get[] = "GET /index.html HTTP/1.0\r\n\r\n"; send( sock, get, strlen(get), 0 ); char buf[256]; int n; printf( "recv data\n" ); while ( 1 ) { n = recv( sock, buf, sizeof(buf)-1, 0 ); if ( n <= 0 ) break; buf[ n ] = '\0'; printf( buf ); } closesocket( sock ); WSACleanup(); } をVC++6.0でコンパイルしたのですが sample_client_win.obj : error LNK2001: 外部シンボル "_WSACleanup@0" は未解決です のようなコンパイルエラーが出て実行できません。これはなにが悪いのでしょうか。本に載っているサンプルコードなのでソース自体は間違っていないと思うのですが・・・もしよろしかったらご教授ください。

専門家に質問してみよう