C でのソケットプログラミング
ソケットプログラミングとは何ですか?
ソケット プログラミングは、ネットワーク上の 2 つのノードを接続して相互に通信する方法です。 1 つのソケット (ノード) は IP の特定のポートで待機し、もう 1 つのソケットは他のソケットに接続して接続を形成します。クライアントがサーバーに接続している間、サーバーはリスナー ソケットを形成します。
サーバーおよびクライアント モデルの状態図
ソケットのサーバーおよびクライアント モデルの状態図
サーバーの段階
サーバーは次の手順で作成されます。
1. ソケットの作成
int sockfd = socket(domain, type, protocol)
- sockfd: ソケット記述子、整数 (ファイル ハンドルなど) ドメイン: 整数、通信ドメインを指定します。同じホスト上のプロセス間の通信には、POSIX 標準で定義されている AF_LOCAL を使用します。 IPV4 で接続された異なるホスト上のプロセス間の通信には、IPV6 で接続されたプロセスには AF_INET と AF_I NET 6 を使用します。タイプ:通信タイプ
SOCK_STREAM: TCP (信頼性の高い接続指向)
SOCK_DGRAM: UDP (信頼性の低い、コネクションレス) プロトコル: インターネット プロトコル (IP) のプロトコル値、0 です。これは、パケットの IP ヘッダーのプロトコル フィールドに表示されるのと同じ番号です。(詳細については man プロトコル)
2. セットソコプト
これは、ファイル記述子 sockfd によって参照されるソケットのオプションを操作するのに役立ちます。これは完全にオプションですが、アドレスとポートの再利用に役立ちます。アドレスがすでに使用されているなどのエラーを防ぎます。
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
3.バインド
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
ソケットの作成後、バインド関数はソケットを addr(カスタム データ構造) で指定されたアドレスとポート番号にバインドします。コード例では、サーバーをローカルホストにバインドするため、INADDR_ANY を使用して IP アドレスを指定します。
4. 聞く
int listen(int sockfd, int backlog);
サーバーソケットをパッシブモードにし、クライアントが接続を確立するためにサーバーに近づくのを待ちます。バックログは、sockfd の保留中の接続のキューが増加する最大長を定義します。キューがいっぱいのときに接続要求が到着すると、クライアントは ECONNREFUSED を示すエラーを受け取ることがあります。
5. 同意する
int new_socket= accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
これは、リッスンしているソケット sockfd の保留中の接続のキューにある最初の接続要求を抽出し、新しい接続されたソケットを作成し、そのソケットを参照する新しいファイル記述子を返します。この時点で、クライアントとサーバー間の接続が確立され、データを転送できる状態になります。
クライアントの段階
1. ソケット接続: サーバーのソケット作成と全く同じ
2. 接続します。 connect() システムコールは、ファイル記述子 sockfd によって参照されるソケットを addr によって指定されたアドレスに接続します。 addrにはサーバーのアドレスとポートを指定します。
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
実装
ここでは、クライアント/サーバー モデルを示すために、サーバーとクライアントの間で 1 つの hello メッセージを交換しています。
サーバーを作成する C プログラム
サーバー.c
C
// Server side C program to demonstrate Socket> // programming> #include> #include> #include> #include> #include> #include> #define PORT 8080> int> main(> int> argc,> char> const> * argv[])> {> > int> server_fd, new_socket;> > ssize_t valread;> > struct> sockaddr_in address;> > int> opt = 1;> > socklen_t addrlen => sizeof> (address);> > char> buffer[1024] = { 0 };> > char> * hello => 'Hello from server'> ;> > // Creating socket file descriptor> > if> ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) <0) {> > perror> (> 'socket failed'> );> > exit> (EXIT_FAILURE);> > }> > // Forcefully attaching socket to the port 8080> > if> (setsockopt(server_fd, SOL_SOCKET,> > SO_REUSEADDR | SO_REUSEPORT, &opt,> > sizeof> (opt))) {> > perror> (> 'setsockopt'> );> > exit> (EXIT_FAILURE);> > }> > address.sin_family = AF_INET;> > address.sin_addr.s_addr = INADDR_ANY;> > address.sin_port = htons(PORT);> > // Forcefully attaching socket to the port 8080> > if> (bind(server_fd, (> struct> sockaddr*)&address,> > sizeof> (address))> > <0) {> > perror> (> 'bind failed'> );> > exit> (EXIT_FAILURE);> > }> > if> (listen(server_fd, 3) <0) {> > perror> (> 'listen'> );> > exit> (EXIT_FAILURE);> > }> > if> ((new_socket> > = accept(server_fd, (> struct> sockaddr*)&address,> > &addrlen))> > <0) {> > perror> (> 'accept'> );> > exit> (EXIT_FAILURE);> > }> > valread = read(new_socket, buffer,> > 1024 - 1);> // subtract 1 for the null> > // terminator at the end> > printf> (> '%s
'> , buffer);> > send(new_socket, hello,> strlen> (hello), 0);> > printf> (> 'Hello message sent
'> );> > // closing the connected socket> > close(new_socket);> > // closing the listening socket> > close(server_fd);> > return> 0;> }> |
クライアントを作成するCプログラム
client.c
C
// Client side C program to demonstrate Socket> // programming> #include> #include> #include> #include> #include> #define PORT 8080> int> main(> int> argc,> char> const> * argv[])> {> > int> status, valread, client_fd;> > struct> sockaddr_in serv_addr;> > char> * hello => 'Hello from client'> ;> > char> buffer[1024] = { 0 };> > if> ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) <0) {> > printf> (> '
Socket creation error
'> );> > return> -1;> > }> > serv_addr.sin_family = AF_INET;> > serv_addr.sin_port = htons(PORT);> > // Convert IPv4 and IPv6 addresses from text to binary> > // form> > if> (inet_pton(AF_INET,> '127.0.0.1'> , &serv_addr.sin_addr)> > <= 0) {> > printf> (> > '
Invalid address/ Address not supported
'> );> > return> -1;> > }> > if> ((status> > = connect(client_fd, (> struct> sockaddr*)&serv_addr,> > sizeof> (serv_addr)))> > <0) {> > printf> (> '
Connection Failed
'> );> > return> -1;> > }> > send(client_fd, hello,> strlen> (hello), 0);> > printf> (> 'Hello message sent
'> );> > valread = read(client_fd, buffer,> > 1024 - 1);> // subtract 1 for the null> > // terminator at the end> > printf> (> '%s
'> , buffer);> > // closing the connected socket> > close(client_fd);> > return> 0;> }> |
出力
Client:Hello message sent Hello from server Server:Hello from client Hello message sent
コンパイル中
gcc client.c -o client gcc server.c -o server
次へ: C/C++ でのソケット プログラミング: マルチスレッドを使用せずにサーバー上で複数のクライアントを処理する