質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.44%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

POSIX

POSIXは、UNIX系OSでの共通機能などを維持するための標準を策定した規格。POSIX仕様によって開発したプログラムは、POSIXに準じたOSであればどれも同じように動作させることが可能です。

ソケット

TCP/IPにおいて、IPアドレスとサブアドレスであるポート番号を組み合わせたネットワークアドレスのことを呼びます。また、ソフトウェアアプリケーションにおいて、TCP/IP通信を行う為の仮想的なインターフェースという意味もある。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Red Hat Enterprise

Red Hat Enterpriseは、レッドハット社により開発・サポートが行われている業務向けLinuxディストリビューションです。オープンソースで無償で利用することができ、バイナリ版の入手・サポートは有償です。商用ディストリビューションとして人気が高く、代表的なLinuxの選択肢の一つです。

Q&A

解決済

2回答

1378閲覧

POSIXスレッドを使用したSOCKET通信実装時のコアダンプエラー

Gurt

総合スコア14

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

POSIX

POSIXは、UNIX系OSでの共通機能などを維持するための標準を策定した規格。POSIX仕様によって開発したプログラムは、POSIXに準じたOSであればどれも同じように動作させることが可能です。

ソケット

TCP/IPにおいて、IPアドレスとサブアドレスであるポート番号を組み合わせたネットワークアドレスのことを呼びます。また、ソフトウェアアプリケーションにおいて、TCP/IP通信を行う為の仮想的なインターフェースという意味もある。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Red Hat Enterprise

Red Hat Enterpriseは、レッドハット社により開発・サポートが行われている業務向けLinuxディストリビューションです。オープンソースで無償で利用することができ、バイナリ版の入手・サポートは有償です。商用ディストリビューションとして人気が高く、代表的なLinuxの選択肢の一つです。

0グッド

0クリップ

投稿2020/07/08 10:10

前提・実現したいこと

POSIXスレッドを使用しクライアントpcからの入力内容をそのまま返すエコーサーバの並列通信を実装しようとしています。

接続要求を待ち,通信用のソケットを作成するacceptまでは処理が完了していると思われるのですが、その後の通信用ソケットディスクリプタ、クライアント番号、アドレス構造体を構造体へセットする際(コメント部2)にsegmentation fault 11のコアダンプを起こしていると思われます。該当する部分の順番を替えたりしてみたのですが同じくコアダンプが起きてしまいます。

発生している問題・エラーメッセージ

Segmentation fault (コアダンプ)

該当のソースコード

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <unistd.h> 5#include <sys/socket.h> 6#include <netinet/in.h> 7#include <arpa/inet.h> 8#include <sys/types.h> 9#include <pthread.h> 10#define BUFSIZE 1024 11#define LISTENQ 1024 12 13void *thread(void *arg); 14 15struct ThreadArgs { 16 int sock; 17 int cnt; 18 struct sockaddr_in sa; 19}; 20 21int main(int argc, char *argv[]){ 22 int listen_sock, comm_sock, sa_len, cnt; 23 struct sockaddr_in sa, new_sa; 24 pthread_t thread_id; 25 struct ThreadArgs *args; 26 listen_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 27 int option = 1; 28 setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); 29 memset(&sa, 0, sizeof(sa));ここに問題に対して試したことを記載してください。 30 sa.sin_family = AF_INET; 31 sa.sin_port = htons(49152); 32 sa.sin_addr.s_addr = htonl(INADDR_ANY); 33 if(bind(listen_sock, (struct sockaddr *)&sa, sizeof(sa)) < 0){ 34 fprintf(stderr, "bind() failure\n"); 35 exit(1); 36 } 37 if(listen(listen_sock, LISTENQ) < 0){ 38 fprintf(stderr, "listen() failure\n"); 39 exit(1); 40 } 41 cnt = 0; 42 while(1){ 43 printf("Waiting for a client\n"); 44 sa_len = sizeof(new_sa); 45 if((comm_sock = accept(listen_sock, (struct sockaddr *)&new_sa, &sa_len)) < 0){ 46 fprintf(stderr, "accept() failure\n"); 47 exit(1); 48 } 49 ++cnt; 50 // 1. 引数用の構造体のメモリを確保する 51 args = (struct ThreadArgs *)malloc(sizeof(struct ThreadArgs)); 52 if(args = NULL){ 53 fprintf(stderr, "malloc() failure\n"); 54 exit(1); 55 } 56/*ここまでは処理できている模様*/ 57 58 // 2. 通信用ソケットディスクリプタ,クライアント番号,アドレス構造体を確保した構造体にセット 59 args->sock = comm_sock; 60 args->cnt = cnt; 61 args->sa = sa; 62 // 3. pthread_create()でスレッドを作成 63 if(pthread_create(&thread_id, NULL, (void *)thread, (void *)args) != 0){ 64 fprintf(stderr, "pthread_create() failure\n"); 65 exit(1); 66 } 67 } 68 return 0; 69} 70 71void *thread(void *arg){ 72 int sock, cnt, n, msg_len; 73 struct sockaddr_in sa; 74 char buf[BUFSIZE]; 75 pthread_detach(pthread_self()); 76 // 4. arg から通信用ソケットディスクリプタ,クライアント番号,アドレス構造体を取得し,それぞれ sock, cnt, sa にセット 77 sock = ((struct ThreadArgs *)arg)->sock; 78 cnt = ((struct ThreadArgs *)arg)->cnt; 79 sa = ((struct ThreadArgs *)arg)->sa; 80 printf("Client %d (%s) connected\n", cnt, inet_ntoa(sa.sin_addr)); 81 if((n = recv(sock, buf, sizeof(buf), 0)) > 0){ 82 buf[n] = '\0'; 83 msg_len = strlen(buf); 84 printf("Client %d: %s\n", cnt, buf); 85 if(send(sock, buf, msg_len, 0) != msg_len){ 86 fprintf(stderr, "send() failure\n"); 87 } 88 } 89 close(sock); 90 printf("Client %d disconnected\n", cnt); 91 free(arg); 92}

試したこと

試すというほどの事ではないのですが該当箇所の型があっているかの確認はしました。

参考にしたプログラム

上がスレッド実装前のエコーサーバプログラム

下がスレッドのみを実装し、それぞれのスレッドで数秒ごとに1~10をカウントするプログラム

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <unistd.h> 5#include <sys/socket.h> 6#include <netinet/in.h> 7#include <arpa/inet.h> 8#include <sys/types.h> 9#define BUFSIZE 1024 10#define LISTENQ 1024 11int main(int argc, char *argv[]) 12{ 13 int listen_sock, comm_sock, msg_len, sa_len, cnt, n; 14 struct sockaddr_in sa, new_sa; 15 char buf[BUFSIZE]; 16 listen_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 17 memset(&sa, 0, sizeof(sa)); 18 sa.sin_family = AF_INET; 19 sa.sin_port = htons(49152); // 49152番ポートで待ち受ける 20 sa.sin_addr.s_addr = htonl(INADDR_ANY); // どんなIPアドレスからでもOK 21 if(bind(listen_sock, (struct sockaddr *)&sa, sizeof(sa)) < 0){ 22 fprintf(stderr, "bind() failure\n"); 23 exit(1); 24 } 25 if(listen(listen_sock, LISTENQ) < 0){ 26 fprintf(stderr, "listen() failure\n"); 27 exit(1); 28 } 29 cnt = 1; 30 while(1){ 31 printf("Waiting for a client\n"); 32 sa_len = sizeof(new_sa); 33 if((comm_sock = accept(listen_sock, (struct sockaddr *)&new_sa, &sa_len)) < 0){ 34 fprintf(stderr, "accept() failure\n"); 35 exit(1); 36 } 37 38 printf("Client %d (%s) connected\n", cnt, inet_ntoa(new_sa.sin_addr)); 39 while(1){ 40 if((n = recv(comm_sock, buf, sizeof(buf), 0)) > 0){ 41 buf[n] = '\0'; 42 msg_len = strlen(buf); 43 printf("Client %d: %s\n", cnt, buf); 44 if(send(comm_sock, buf, msg_len, 0) != msg_len){ 45 fprintf(stderr, "send() failure\n"); 46 exit(1); 47 } 48 } 49 } 50 close(comm_sock); 51 printf("Client %d disconnected\n", cnt); 52 ++cnt; 53 } 54 return 0; 55}

c

1#include <stdio.h> 2#include <unistd.h> 3#include <stdlib.h> 4#include <pthread.h> 5 6void *thread(void *arg); 7 8struct ThreadArgs{ 9 int sec; 10 char *msg; 11}; 12 13int main(int argc, char *argv[]){ 14 pthread_t thread_id1, thread_id2, thread_id3; 15 struct ThreadArgs *args; 16 17 args = (struct ThreadArgs *)malloc(sizeof(struct ThreadArgs)); 18 if(args == NULL){ 19 fprintf(stderr, "malloc() failure\n"); 20 exit(1); 21 } 22 args->sec = 1; 23 args->msg = "thread1"; 24 if(pthread_create(&thread_id1, NULL, (void *)thread, (void *)args) != 0){ 25 fprintf(stderr, "pthread_create() failure\n"); 26 exit(1); 27 } 28 29 args = (struct ThreadArgs *)malloc(sizeof(struct ThreadArgs)); 30 if(args == NULL){ 31 fprintf(stderr, "malloc() failure\n"); 32 exit(1); 33 } 34 args->sec = 2; 35 args->msg = "thread2"; 36 if(pthread_create(&thread_id2, NULL, (void *)thread, (void *)args) != 0){ 37 fprintf(stderr, "pthread_create() failure\n"); 38 exit(1); 39 } 40 41 args = (struct ThreadArgs *)malloc(sizeof(struct ThreadArgs)); 42 if(args == NULL){ 43 fprintf(stderr, "malloc() failure\n"); 44 exit(1); 45 } 46 args->sec = 3; 47 args->msg = "thread3"; 48 if(pthread_create(&thread_id3, NULL, (void *)thread, (void *)args) != 0){ 49 fprintf(stderr, "pthread_create() failure\n"); 50 exit(1); 51 } 52 53 pthread_join(thread_id1, NULL); 54 pthread_join(thread_id2, NULL); 55 pthread_join(thread_id3, NULL); 56 return 0; 57 } 58 59void *thread(void *arg){ 60 int sec, i; 61 char *msg; 62 sec = ((struct ThreadArgs *)arg)->sec; 63 msg = ((struct ThreadArgs *)arg)->msg; 64 for(i=0; i<10; i++){ 65 sleep(sec); 66 printf("%s %lu: %d\n", msg, pthread_self(), i+1); 67 } 68 free(arg); 69}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2020/07/08 10:34

struct ThreadArgs型のargs はmainで1つだけmallocして共有しているわけですから、3つのスレッドそれぞれの終了時にfreeしてはダメです。3重で解放してます。それでコアダンプ、では。
dodox86

2020/07/08 10:45 編集

今のかたちであれば、3つのスレッドをpthread_joinで終わらせてからmain関数内でfreeするのが適切です。それで直ったら原因、対応策をまとめて自己回答、解決で質問を閉じてください。直らなかったら質問に追記ください。
angel_p_57

2020/07/08 13:49

いや、理由はそこではないでしょう。
Gurt

2020/07/08 15:30

自分の考えでは参考にしたスレッドプログラムではスレッド数が3つと決まっていて処理内容も決まっていたのでpthread_joinでスレッドの終了を待機させている。今回のプログラムではクライアント1つ1つにスレッドを与えるのでスレッド数が決まっていない為、void *thread(void *args)の中でpthread_detachを行いスレッドを終了していると思っています。 ご指摘のmainでargsをmallocしそれぞれのスレッドで解放しているということは、参考にしたスレッドプログラムではそれぞれのスレッドで1〜10までカウントし処理が完了してからそのスレッドで使っていた構造体の解放という認識だったので、今回のプログラムでもそれぞれのスレッドで使用している構造体をクライアントの切断を確認してから解放という認識で書きました。 スレッド数が決まっていない今回のプログラムではスレッドが終了するまで待機できるpthread_joinが使えないと思った為、mainでの解放は処理の終わっていないスレッドの構造体までも解放するのではないかと思い実装しませんでした。
dodox86

2020/07/08 16:00 編集

angel_p_57さん、ご指摘どうもありがとうございます。コアダンプの直接の原因については完全に私の見落としでした。 >@Gurtさん > 今回のプログラムでもそれぞれのスレッドで使用している構造体をクライアントの切断を確認してから解放という認識で書きました。 mainで取得した単一のメモリ領域なので、今回の件に関してはそれではまずいですね。acceptでクラインと接続確認後、それぞれのスレッド用に改めて割り当てるような形であればOKですが。
guest

回答2

0

ベストアンサー

ソースは質問にあるままでよろしいでしょうか?
それだとargsをNULL比較するつもりで代入しちゃってるので、ポインタ参照で落ちますよね。

if(args = NULL){ fprintf(stderr, "malloc() failure\n"); exit(1); } /*ここまでは処理できている模様*/ // 2. 通信用ソケットディスクリプタ,クライアント番号,アドレス構造体を確保した構造体にセット args->sock = comm_sock;

投稿2020/07/08 13:51

angel_p_57

総合スコア1681

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Gurt

2020/07/08 15:39

ありがとうございます。無事に解決いたしました。 コアダンプの発生が通信用ソケットディスクリプタ,クライアント番号,アドレス構造体を確保した構造体にセットしているときにおこっているものだと思い込んでいた為ThreadArgsの中身の型がおかしいとばかり思い、int型の配列にしたりと見当違いなことをしていました。 通常のifの比較などでは=が足りないよというエラーが出ていたので油断していました。今回の書き方だとポインタにNULLを代入してしまうのですね
guest

0

そういうコアダンプやらメモリエラーが出るときはどこかでメモリ破壊や不正アクセスが起こっているということですね。
その状態でいくらコードをいじっても無駄です。
そのメモリ破壊の箇所を探して修正しないとだめですね

投稿2020/07/08 10:38

y_waiwai

総合スコア87840

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.44%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問