socketネットワークプログラミングの集中操作

10611 ワード

1、socket()関数
int socket(int domain, int type, int protocol);

socket関数は、通常のファイルの開く操作に対応します.通常のファイルの開く操作はファイル記述語を返し、socket()はsocket記述子(socket descriptor)を作成するために使用され、socketはsocketを一意に識別します.このsocket記述字はファイル記述字と同様に、後続の操作に役立ち、パラメータとして読み書き操作を行います.fopenに異なるパラメータ値を入力して、異なるファイルを開くことができます.SOcketを作成する場合は、異なるパラメータを指定して異なるsocket記述子を作成することもできます.socket関数の3つのパラメータは、domain:すなわちプロトコルドメインであり、プロトコルファミリーとも呼ばれます.よく使われるプロトコルファミリーは、AF_INET、AF_INET6、AF_LOCAL(またはAF_UNIX、Unixドメインsocket)、AF_ROUTEなど.プロトコルファミリーはsocketのアドレスタイプを決定し、通信にはAF_などの対応するアドレスを採用しなければならない.INETはipv 4アドレス(32ビット)とポート番号(16ビット)の組み合わせ、AF_UNIXはアドレスとして絶対パス名を使用することを決定した.type:socketタイプを指定します.よく使うソケットタイプは、SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQACK ETなど.protocol:だから名前は、プロトコルを指定することです.よく使われるプロトコルは、IPPROTO_です.TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPCなどは、それぞれTCPトランスポートプロトコル、UDPトランスポートプロトコル、STCPトランスポートプロトコル、TIPCトランスポートプロトコルに対応しています(このプロトコルは単独で議論します!).注意:上のtypeとprotocolが勝手に組み合わせられるわけではありません.例えばSOCK_STREAMとIPPROTO_は不可UDPグループ.protocolが0の場合、typeタイプに対応するデフォルトプロトコルが自動的に選択されます.SOcketを呼び出してsocketを作成すると、返されるsocket記述語はプロトコルファミリー(address family,AF_XXX)空間に存在するが、具体的なアドレスはない.アドレスを割り当てるにはbind()関数を呼び出す必要があります.そうしないと、connect()、listen()を呼び出すと、ポートが自動的にランダムに割り当てられます.2、bind()関数
前述したbind()関数は、1つのアドレスファミリー内の特定のアドレスをsocketに付与する.例えば対応AF_INET、AF_INET 6は、ipv 4またはipv 6アドレスとポート番号を組み合わせてsocketに割り当てます.
int bind(int sockfd, conststruct sockaddr *addr, socklen_t addrlen);

関数の3つのパラメータは、sockfd、すなわちsocket記述語であり、socket()関数によって作成され、socketを一意に識別する.bind()関数は,この記述語に名前をバインドする.addr:const struct sockaddr*ポインタで、sockfdにバインドするプロトコルアドレスを指します.このアドレス構造は、ipv 4に対応するように、アドレス作成時のアドレスプロトコルファミリーによって異なります.
struct sockaddr_in {
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order */struct in_addr sin_addr;   /* internet address */
};

/* Internet address. */struct in_addr {
    uint32_t       s_addr;     /* address in network byte order */
};
ipv6    : 
struct sockaddr_in6 { 
    sa_family_t     sin6_family;   /* AF_INET6 */ 
    in_port_t       sin6_port;     /* port number */ 
    uint32_t        sin6_flowinfo; /* IPv6 flow information */struct in6_addr sin6_addr;     /* IPv6 address */ 
    uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ 
};

struct in6_addr { 
    unsignedchar   s6_addr[16];   /* IPv6 address */ 
};

Unixドメインは次のとおりです.
#define UNIX_PATH_MAX    108

struct sockaddr_un { 
    sa_family_t sun_family;               /* AF_UNIX */char        sun_path[UNIX_PATH_MAX];  /* pathname */ 
};

addrlen:アドレスの長さに対応します.通常、サーバは起動時によく知られているアドレス(ipアドレス+ポート番号など)をバインドし、サービスを提供するために、お客様はそれを通じてサーバを接続することができます.クライアントは指定する必要はなく、ポート番号と自身のipアドレスの組み合わせを自動的に割り当てるシステムがあります.これは、通常、サーバ側がlistenの前にbind()を呼び出すが、クライアントは呼び出さず、connect()時にシステムによってランダムに生成されるためである.ネットワークバイト順とホストバイト順
ホストのバイト順は、一般的に言われている大端モードと小端モードです.CPUによって異なるバイト順タイプがあります.これらのバイト順は、整数がメモリに保存される順序を指し、これをホスト順と言います.参照規格のBig-EndianとLittle-Endianの定義は以下の通りである:a)Little-Endianは、低ビットバイトがメモリの低アドレス端子に排出され、高ビットバイトがメモリの高アドレス端子に排出される.b)Big-Endianは,メモリの低アドレス端子に上位バイトが排出され,メモリの高アドレス端子に下位バイトが排出される.ネットワークバイト順:4バイトの32 bit値は、まず0~7 bit、次いで8~15 bit、次いで16~23 bit、最後に24~31 bitの順で伝送される.この伝送順序は、エンドバイトシーケンスと呼ばれる.TCP/IPヘッダのすべてのバイナリ整数は、ネットワークで伝送される際にこのような順序で要求されるため、ネットワークバイトシーケンスとも呼ばれる.バイトシーケンスとは、その名の通りバイトの順序であり、1バイトタイプより大きいデータのメモリへの格納順序であり、1バイトのデータに順序がないという問題である.したがって、1つのアドレスをsocketにバインドする場合は、まずホストバイト順をネットワークバイト順に変換し、ホストバイト順がネットワークバイト順と同じようにBig-endianを使用していると仮定しないでください.この問題で血事件を起こしたことがある!会社のプロジェクトコードにはこの問題が存在し、わけのわからない問題が多いので、ホストのバイト順を仮定せずに、必ずネットワークのバイト順に変換してsocketに割り当ててください.3、listen()、connect()関数
サーバとしてsocket()、bind()を呼び出すとlisten()が呼び出されてこのsocketを傍受し、クライアントがconnect()を呼び出して接続要求を発行すると、サーバ側はこの要求を受信する.
int listen(int sockfd, int backlog);
int connect(int sockfd, conststruct sockaddr *addr, socklen_t addrlen);

Listen関数の最初のパラメータは、リスニングするsocket記述語であり、2番目のパラメータは、対応するsocketがキューできる最大接続数である.socket()関数で作成されるsocketのデフォルトはアクティブなタイプで、listen関数はsocketをパッシブなタイプに変更し、お客様の接続要求を待っています.connect関数の最初のパラメータはクライアントのsocket記述語であり、第2のパラメータはサーバのsocketアドレスであり、第3のパラメータはsocketアドレスの長さである.クライアントはconnect関数を呼び出すことでTCPサーバとの接続を確立する.4、accept()関数
TCPサーバ側がsocket()、bind()、listen()を順次呼び出すと、指定したsocketアドレスが傍受されます.TCPクライアントはsocket(),connect()を順次呼び出した後,TCPサーバに接続要求を送信したと考える.TCPサーバはこのリクエストを傍受するとaccept()関数を呼び出してリクエストを受信し,接続が確立する.その後、ネットワークI/O操作を開始することができます.つまり、通常のファイルと同じ読み書きI/O操作です.
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

accept関数の最初のパラメータはサーバのsocket記述語であり、2番目のパラメータはstruct sockaddr*を指すポインタであり、クライアントのプロトコルアドレスを返すために使用され、3番目のパラメータはプロトコルアドレスの長さである.accpetが成功した場合、その戻り値は、戻りクライアントとのTCP接続を表すカーネルによって自動的に生成される新しい記述語である.注意:acceptの最初のパラメータはサーバのsocket記述語であり、サーバがsocket()関数を呼び出して生成し始めたものであり、リスニングsocket記述語と呼ばれる.accept関数は、接続されたsocket記述語を返します.1つのサーバは、通常、サーバのライフサイクル中に常に存在するリスニングsocket記述語を1つだけ作成します.カーネルは、サーバプロセスによって受け入れられるクライアント接続ごとに接続されたsocket記述語を作成し、サーバがクライアントへのサービスを完了すると、対応する接続されたsocket記述語が閉じられます.5、read()、write()などの関数
すべてのことは東風に欠けているだけで、サーバとお客様はすでに接続を確立しています.ネットワークI/Oを呼び出して読み書き操作を行うことができ、すなわち、ネット上の異なるプロセス間の通信を実現することができる!ネットワークI/O操作には次のグループがあります.
read()/write()
recv()/send()
readv()/writev()
recvmsg()/sendmsg()
recvfrom()/sendto()

recvmsg()/sendmsg()関数をお勧めします.この2つの関数は最も一般的なI/O関数で、実際には上の他の関数をこの2つの関数に置き換えることができます.次のように宣言されています.
 #include 

       ssize_t read(int fd, void *buf, size_t count);
       ssize_t write(int fd, constvoid *buf, size_t count);

       #include 
       #include 

       ssize_t send(int sockfd, constvoid *buf, size_t len, int flags);
       ssize_t recv(int sockfd, void *buf, size_t len, int flags);

       ssize_t sendto(int sockfd, constvoid *buf, size_t len, int flags,
                      conststruct sockaddr *dest_addr, socklen_t addrlen);
       ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);

       ssize_t sendmsg(int sockfd, conststruct msghdr *msg, int flags);
       ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

read関数は、fdからのコンテンツの読み出しを担当する.読み取りに成功するとreadは実際に読み込まれたバイト数を返し、返された値が0であればファイルの終了を表し、0未満であればエラーを表す.エラーがEINTRの場合、読み取りが中断によって引き起こされたことを示し、ECONNRESTの場合、ネットワーク接続に問題があることを示します.write関数はbufのnbytesバイトの内容をファイル記述子fdに書き込む.成功したときにライトされたバイト数を返します.失敗した場合は-1を返し、errno変数を設定します.ネットワークプログラムでは、ソケットファイル記述子に書く場合に2つの可能性があります.1)writeの戻り値は0より大きく,一部または全部のデータが書かれていることを示す.2)返される値が0未満の場合、エラーが発生します.私たちはエラーのタイプに基づいて処理します.エラーがEINTRの場合は、書き込み中に割り込みエラーが発生したことを示します.EPIPEに対してネットワーク接続に問題が発生したことを示す場合(相手はすでに接続を閉じている).その他のI/O関数については、manドキュメントまたはbaidu、Googleを参照してください.次の例ではsend/recvに使用します.6、close()関数
サーバがクライアントと接続を確立すると、開いているファイルを操作し終わったらfcloseを呼び出して開いているファイルを閉じるなど、読み書き操作が完了すると、対応するsocket記述語を閉じます.
#include 
int close(int fd);

close TCP socketのデフォルト動作では、そのsocketをオフにマークし、すぐに呼び出しプロセスに戻ります.この記述語は、呼び出しプロセスによって使用されなくなり、すなわちreadまたはwriteの最初のパラメータとして使用されなくなる.注意:close操作は、対応するsocket記述ワードの参照カウント-1のみを使用し、参照カウントが0の場合にのみ、TCPクライアントがサーバに接続終了要求を送信するようにトリガします.