【C言語】第10章第7回:ネットワークチャットプログラム
本記事では、C言語を用いて基本的なネットワークチャットプログラムを作成します。ソケット通信の基本概念や、サーバーとクライアントの実装方法を学びます。
0. 記事の概要
この記事を読むメリット
- ネットワークプログラミングの基礎理解:ソケット通信を用いた基本的なクライアントサーバーモデルを学べます。
- 通信プログラムの実践的知識:データ送受信の仕組みや、エラー処理の重要性を理解します。
- 応用力の向上:チャットプログラムを基に、他のネットワークアプリケーションの構築が可能です。
この記事で学べること
- ソケット通信の基本概念
- サーバーとクライアントの実装
- データ送受信の方法
1. ネットワークチャットプログラムの基本設計
1.1 ソケット通信とは?
ソケット通信は、ネットワーク間でデータを送受信するための仕組みです。サーバーとクライアントの役割があり、以下の手順で通信が行われます。
- サーバーがソケットを作成してリッスン状態になる。
- クライアントがサーバーに接続要求を送る。
- 接続が確立されると、データの送受信が可能になる。
1.2 必要なプログラム構造
ネットワークチャットプログラムは、以下の部分で構成されます。
- サーバー側の実装(リッスンと接続処理)
- クライアント側の実装(サーバーへの接続処理)
- データ送受信の処理
2. コード例と詳細解説
2.1 サーバー側コード例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = {0};
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("ソケットの作成に失敗しました");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("バインドに失敗しました");
close(server_fd);
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0) {
perror("リッスンに失敗しました");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("サーバーがポート%dでリッスン中...\n", PORT);
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("接続の受け入れに失敗しました");
close(server_fd);
exit(EXIT_FAILURE);
}
while (1) {
memset(buffer, 0, BUFFER_SIZE);
int valread = read(new_socket, buffer, BUFFER_SIZE);
if (valread <= 0) break;
printf("クライアント: %s\n", buffer);
printf("メッセージを入力してください: ");
fgets(buffer, BUFFER_SIZE, stdin);
send(new_socket, buffer, strlen(buffer), 0);
}
close(new_socket);
close(server_fd);
return 0;
}
2.2 クライアント側コード例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char buffer[BUFFER_SIZE] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("ソケットの作成に失敗しました");
exit(EXIT_FAILURE);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
perror("無効なアドレスです");
exit(EXIT_FAILURE);
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("接続に失敗しました");
exit(EXIT_FAILURE);
}
while (1) {
printf("メッセージを入力してください: ");
fgets(buffer, BUFFER_SIZE, stdin);
send(sock, buffer, strlen(buffer), 0);
memset(buffer, 0, BUFFER_SIZE);
int valread = read(sock, buffer, BUFFER_SIZE);
if (valread <= 0) break;
printf("サーバー: %s\n", buffer);
}
close(sock);
return 0;
}
動作解説
- サーバー側:ソケットを作成し、指定したポートでリッスンします。接続を受け入れた後、データの送受信を処理します。
- クライアント側:サーバーに接続し、ユーザー入力を送信し、サーバーからの返信を受信します。
- データ送受信:`read`と`send`関数を使用してメッセージを交換します。
3. 練習問題
以下の課題に挑戦して、ネットワークチャットプログラムを拡張してみましょう。
- 複数のクライアントをサポートする機能を追加してください。
- メッセージにタイムスタンプを付加してください。
- メッセージ履歴をサーバー側でログファイルに保存してください。
4. 練習問題の解答と解説
問3の解答例
// メッセージ履歴の保存
void logMessage(const char *message) {
FILE *logfile = fopen("chat.log", "a");
if (logfile) {
fprintf(logfile, "%s\n", message);
fclose(logfile);
}
}
この関数をサーバーのメッセージ処理部分に組み込むことで、すべてのメッセージが`chat.log`ファイルに記録されます。
5. まとめ
本記事では、C言語を用いてネットワークチャットプログラムを実装しました。さらに高度な機能を追加して、より実用的なアプリケーションに進化させてみましょう。