TCP/UDPを実現するシンプルなEchoサーバ
10380 ワード
シリーズブログリファレンス:http://blog.csdn.net/zy416548283/article/category/1108400コードは番号対応でGithubに置かれます.https://github.com/zy416548283/networkProgramming
タイトル
ネットワーク上のEchoサーバは,それぞれ接続向けと無接続の方式で実現される.Echoサーバは、クライアントがサーバに文字列を送信し、サーバが受信した後、クライアントに同じ文字列を返す.
タイトル解読 TCPとUDPの基本的なSocket APIを熟知している. サーバとクライアントのプログラムフローを熟知している. TCPとUDPプログラミングの違いを熟知している. プロセスで発生する可能性のあるいくつかの異常状況は、どのように処理し、プログラムの丈夫性を保証するか. 同時サーバと反復サーバの違い.
インプリメンテーション
宣言:プログラムはUNP第5章と第8章から取られ、UNPのソースコードの取得とコンパイルについては本シリーズの文章を参照することができる.
TCP(接続向け):
サーバ側:
サーバ側のプロセス:ソケットの作成–いくつかのパラメータの初期化–ポートのバインド–リスニング–接続の受け入れ–新しい接続を処理するためのサブプロセスの作成–接続を閉じることがわかります.ここで、文字列を処理する関数は次のとおりです.
client
Client側の実行プロセス:ソケットの作成–パラメータの初期化–サーバへの接続–文字列の送信と受信–プログラムの終了(ソケットのクローズ)が表示されます.ここでstr_cliは次のとおりです.
プログラムのコンパイル/実行
サーバ側:
Client:
注意事項 netstatコマンドを使用してソケットの状態を表示し、通常のTCPの状態変換を理解することができる. 硬直プロセス、waitとwaitpidの使用を処理する. サーバプロセスが終了し、クライアントが入力状態にあり、サーバから終了メッセージをどのように受信するか、selectのソリューションを考慮する. サーバホストがクラッシュしました. サーバホストがクラッシュした後に再起動します.
UDP
Server
UDPサーバ側のプロセスは、ソケットの作成–初期化パラメータ–バインドポート–反復処理要求–終了(ソケットを閉じる)です.dg_echoは次のとおりです.
ここではTCPの同時処理とは異なり,反復処理要求を採用している.TCPは長い接続を維持する可能性があり、1つの要求を出さずに閉じるため、サーバを占有する必要があるため、同時使用を採用します.ここでのUDPはショートメッセージを処理し,バッファからFIFOでメッセージを処理し,反復的に処理する.具体的にはブログを参照してください.http://blog.csdn.net/lianghe_work/article/details/46500893
client
udp client側のプロセスは、ソケットの作成–パラメータの初期化–受信データの送信–プログラムの終了(ソケットのクローズ)であり、dg_cli関数は次のとおりです.
コンパイルと実行
上記TCPのコンパイル運転方式と一致
注意事項 clientはサーバより先に実行され、お客様がrecvfromにブロックされます.ここでconnectを使用するとsendtoのエラーを検出したり、recvfromにタイムアウト待ち時間を設定したりすることができます. UDPは流量制御に欠けており、Client側がデータを狂って送信すると受信側が水没する. は、UDPの信頼性をどのように高めるかを考慮することができる.
文章が役に立つと思ったら、支付宝でポイントを打つことができます:
タイトル
ネットワーク上のEchoサーバは,それぞれ接続向けと無接続の方式で実現される.Echoサーバは、クライアントがサーバに文字列を送信し、サーバが受信した後、クライアントに同じ文字列を返す.
タイトル解読
インプリメンテーション
宣言:プログラムはUNP第5章と第8章から取られ、UNPのソースコードの取得とコンパイルについては本シリーズの文章を参照することができる.
TCP(接続向け):
サーバ側:
//tcpserver
#include "unp.h"
int
main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
for ( ; ; ) {
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
if ( (childpid = Fork()) == 0) { /* child process */
Close(listenfd); /* close listening socket */
str_echo(connfd); /* process the request */
exit(0);
}
Close(connfd); /* parent closes connected socket */
}
}
サーバ側のプロセス:ソケットの作成–いくつかのパラメータの初期化–ポートのバインド–リスニング–接続の受け入れ–新しい接続を処理するためのサブプロセスの作成–接続を閉じることがわかります.ここで、文字列を処理する関数は次のとおりです.
void
str_echo(int sockfd)
{
ssize_t n;
char buf[MAXLINE];
again:
while ( (n = read(sockfd, buf, MAXLINE)) > 0)
Writen(sockfd, buf, n);
if (n < 0 && errno == EINTR)
goto again;
else if (n < 0)
err_sys("str_echo: read error");
}
client
#include "unp.h"
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: tcpcli <IPaddress>");
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));
str_cli(stdin, sockfd); /* do it all */
exit(0);
}
Client側の実行プロセス:ソケットの作成–パラメータの初期化–サーバへの接続–文字列の送信と受信–プログラムの終了(ソケットのクローズ)が表示されます.ここでstr_cliは次のとおりです.
#include "unp.h"
void
str_cli(FILE *fp, int sockfd)
{
char sendline[MAXLINE], recvline[MAXLINE];
while (Fgets(sendline, MAXLINE, fp) != NULL) {
Writen(sockfd, sendline, strlen(sendline));
if (Readline(sockfd, recvline, MAXLINE) == 0)
err_quit("str_cli: server terminated prematurely");
Fputs(recvline, stdout);
}
}
プログラムのコンパイル/実行
サーバ側:
gcc tcpserv01.c -o server01 -lunp
./server01
Client:
gcc tcpcli01.c -o client01 -lunp
./client01 127.0.0.1
注意事項
UDP
Server
#include "unp.h"
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(sockfd, (SA *) &servaddr, sizeof(servaddr));
dg_echo(sockfd, (SA *) &cliaddr, sizeof(cliaddr));
}
UDPサーバ側のプロセスは、ソケットの作成–初期化パラメータ–バインドポート–反復処理要求–終了(ソケットを閉じる)です.dg_echoは次のとおりです.
#include "unp.h"
void
dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];
for ( ; ; ) {
len = clilen;
n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
Sendto(sockfd, mesg, n, 0, pcliaddr, len);
}
}
ここではTCPの同時処理とは異なり,反復処理要求を採用している.TCPは長い接続を維持する可能性があり、1つの要求を出さずに閉じるため、サーバを占有する必要があるため、同時使用を採用します.ここでのUDPはショートメッセージを処理し,バッファからFIFOでメッセージを処理し,反復的に処理する.具体的にはブログを参照してください.http://blog.csdn.net/lianghe_work/article/details/46500893
client
#include "unp.h"
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: udpcli <IPaddress>");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));
exit(0);
}
udp client側のプロセスは、ソケットの作成–パラメータの初期化–受信データの送信–プログラムの終了(ソケットのクローズ)であり、dg_cli関数は次のとおりです.
#include "unp.h"
void
dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
while (Fgets(sendline, MAXLINE, fp) != NULL) {
Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}
コンパイルと実行
上記TCPのコンパイル運転方式と一致
注意事項
文章が役に立つと思ったら、支付宝でポイントを打つことができます: