Linux c開発-Socket

11544 ワード

Socketの英語の原義は「穴」または「コンセント」です.BSD UNIXのプロセス通信メカニズムとして,次の意味をとる.通常は「ソケット」とも呼ばれ、IPアドレスとポートを記述するために使用され、通信チェーンのハンドルである.インターネット上のホストでは、一般的に複数のサービスソフトウェアが実行され、いくつかのサービスが提供されています.各サービスはSocketを開き、異なるポートが異なるサービスに対応するポートにバインドされます.
サービス側の例
まず、マルチスレッド、マルチユーザ接続をサポートするブロックIOモードのSOCKETの例を見る.なぜIOがブロックされているのか、私の文章を参考にしてください.http://blog.csdn.net/initphp/article/details/42011845
スレッドが使用されているため、例のコンパイル:
gcc main.c -o main -lpthread

      
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h> 
#include <pthread.h>  

//          
typedef struct args {
    int client_socketfd;
} ARGS;

//       
void * recv_msg(void * args) {

    ARGS * args_p = (ARGS * ) args;

    //      
    char * msg = "Welcome to My socket";
    int size = send(args_p->client_socketfd, msg, strlen(msg), 0);

    //        
    char buf[1024];  //          
    int len;
    while ((len = recv(args_p->client_socketfd, buf, 1024, 0)) > 0) {  
        buf[len] = '\0';  
        printf("%s
", buf); if (send(args_p->client_socketfd, buf, len, 0) < 0) { perror("write"); } } free(args_p); // shutdown(args_p->client_socketfd, 2); // socketid } int server() { int server_socketfd; // socket struct sockaddr_in server_addr; // memset(&server_addr,0,sizeof(server_addr)); // -- server_addr.sin_family = AF_INET; // IP server_addr.sin_addr.s_addr = INADDR_ANY;// IP -- server_addr.sin_port = htons(8000); // // server_socketfd = socket(PF_INET,SOCK_STREAM,0); if (server_socketfd < 0) { puts("socket error"); return 0; } // IP if (bind(server_socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))<0) { puts("bind error"); return 0; } // , 5 listen(server_socketfd, 1); // while (1) { int client_socketfd;// struct sockaddr_in client_addr; // int in_size = sizeof(struct sockaddr_in); // socket client_socketfd = accept(server_socketfd, (struct sockaddr *) &client_addr, &in_size); // , if (client_socketfd < 0) { puts("accpet error"); return 0; } printf("IP :%s", inet_ntoa(client_addr.sin_addr)); // , , free, ARGS *args = (ARGS *) malloc(sizeof (ARGS *)); args->client_socketfd = client_socketfd; pthread_t t1; int x = pthread_create(&t1, NULL , recv_msg, args); // if (x != 0) { puts(" "); } } shutdown(server_socketfd, 2); // socket } int main(void) { server(); // Server return 0; }

クライアントの例
クライアントの例を見ることができます.この例は主にsocketによってサービス側に接続され、サービス側にメッセージを送信し、応答を受信する.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h> 
#include <pthread.h>  

int main() {
	
	int client_fd; //        SOCKET

	struct sockaddr_in server_addr; //    
	memset(&server_addr,0,sizeof(server_addr)); //     --    
    server_addr.sin_family=AF_INET; //   IP    
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//   IP    
    server_addr.sin_port = htons(8000); //        

    client_fd = socket(PF_INET, SOCK_STREAM, 0);
    if (client_fd < 1) {
    	puts("client socket error");
    	return 0;
    }

 	/*                ,        */  
    int ret = connect(client_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
    if (ret < 0) {
    	puts("client connect error!");
    	return 0;
    }

    char buf[1024];
    int len = recv(client_fd, buf, 1024, 0); //           
    buf[len] = '\0';
    puts(buf);

    char *x = "Hello World";
    send(client_fd, x, strlen(x), 0); //    

	memset(buf, 0, 1024);
    int len2 = recv(client_fd, buf, 1024, 0); //            
    buf[len2] = '\0';
    puts(buf);

    shutdown(client_fd,2); //  socket

}

共通インタフェース
1.socket()関数
関数の定義:
int socket(int domain, int type, int protocol);
socket関数は、新しいsocketを確立するために使用され、すなわち、システムに登録し、通信ポートを確立することを通知する.
パラメータ:
1.domainは、どのアドレスタイプを使用するかを指定します.
プロトコル
説明
PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL
UNIXプロセス通信プロトコル
PF_INET/AF_INET
Ipv 4ネットワークプロトコル
PF_INET6/AF_INET6
Ipv 6ネットワークプロトコル
PF_IPX/AF_IPX IPX-Novell
プロトコル
PF_NETLINK/AF_NETLINK
コアユーザインタフェース装置
PF_X25/AF_X25
ITU-T X.25/ISO-8208プロトコル
PF_AX25/AF_AX25
アマチュア無線AX25プロトコル
PF_ATMPVC/AF_ATMPVC
元ATM PVCsへのアクセス
PF_APPLETALK/AF_APPLETALK
Appletalk(DDP)プロトコル
PF_PACKET/AF_PACKET
プライマリパッケージインタフェース
PF_INET/AF_INET
Ipv 4ネットワークプロトコル
PF_INET/AF_INET
Ipv 4ネットワークプロトコル
2.typeのカテゴリ.表を参照:
を選択します.
説明
SOCK_STREAM
双方向連続かつ信頼性の高いデータストリーム、すなわちTCPを提供する
SOCK_DGRAM
不連続で信頼できないパケット接続を使用
SOCK_SEQPACKET
継続的で信頼性の高いパケット接続を提供
SOCK_RAW
元のネットワーク・プロトコル・アクセスの提供
SOCK_RDM
信頼性の高いパケット接続を提供
SOCK_PACKET
ネットワークドライバとの直接通信の提供
3.protocolは、socketで使用されるトランスポートプロトコル番号を指定するために使用されます.通常は0です.
戻り値:
成功するとsocket処理コードが返され、失敗すると-1が返されます.
エラーコード:
1、EPROTONOSUPPORTパラメータdomain指定のタイプはパラメータtypeまたはprotocol指定のプロトコル2、ENFILEコアメモリ不足、新しいsocket構造を確立できない3、EMFILEプロセスファイル表オーバーフロー、新しいsocket 4、EACCESS権限不足、typeまたはprotocol指定のプロトコル5、ENOBUFS/ENOMEMメモリ不足6、EINVALパラメータdomain/type/protocolが不正
2.bind()関数
関数の定義:
int bind(int sockfd, struct sockaddr * my_addr, int addrlen);
bind()は、パラメータsockfdのsocketの名前を設定するために使用される.
成功すると0が返され、失敗すると-1が返されます.
エラーコード:
1.EBADFパラメータsockfd非合法socket処理コード.2、EACCESS権限不足3、ENOTSOCKパラメータsockfdはファイル記述語であり、socketではない.
例:
 //  IP
    if (bind(server_socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))<0) {
        puts("bind error");
        return 0;
    }

3.listen()待機接続
関数の定義:
int listen(int s, int backlog);
listen()は、パラメータsのsocket接続を待つために使用される.
Listen()はSOCK_のみ適用STREAMまたはSOCK_SEQACK ETのsocketタイプ.SOcketがAF_の場合INETはパラメータbacklogの最大値を128に設定ことができる.
パラメータ:
1.パラメータsすなわちsocketfd
2.パラメータbacklogは同時に処理できる最大接続要求を指定し、接続数がこの上限に達するとclient側はECONNREFUSEDのエラーを受け取る. 
戻り値:
成功すると0が返され、失敗すると-1が返されます.
エラーコード:
1.EBADFパラメータsockfd非合法socket処理コード2.EACCESSの権限が3.EOPNOTSUPPが指定するsocketはlistenモードをサポートしていない.
例:
    //  ,       5
    listen(server_socketfd, 1);

4.accept()接続を受け入れる
関数の定義:
int accept(int s, struct sockaddr * addr, int * addrlen);
accept()は、パラメータsのsocket接続を受け入れるために用いる.パラメータsのsocket
まずbind()とlisten()関数で処理する必要があり、接続が入るとaccept()は新しいsocket処理コードを返し、その後のデータ転送と読み取りは新しいsocket処理を経由し、元のパラメータsのsocketはaccept()を引き続き使用して新しい接続要求を受け入れることができる.
接続に成功すると、パラメータaddrが指す構造はシステムによってリモートホストのアドレスデータに埋め込まれ、パラメータaddrlenはscokaddrの構造長である.
戻り値:
成功すると新しいsocket処理コードが返され、失敗すると-1が返されます.
エラーコード:
1.EBADFパラメータs非合法socket処理コード.2、EFAULTパラメータaddrポインタはアクセスできないメモリ空間を指す.3、ENOTSOCKパラメータsはファイル記述語であり、socketではない.4、EOPNOTSUPP指定のソケットがSOCK_ではないSTREAM. 5.EPERMファイアウォールはこの接続を拒否する.6、ENOBUFSシステムのバッファメモリが不足している.7、ENOMEMコアのメモリが不足している.
例:
  int client_socketfd;//        
        struct sockaddr_in client_addr; //           
        int in_size = sizeof(struct sockaddr_in);

        //   socket
        client_socketfd = accept(server_socketfd, (struct sockaddr *) &client_addr, &in_size); //      ,       

5.connect()socket接続の確立
関数の定義:
int connect(int sockfd, struct sockaddr * serv_addr, int addrlen);

connect()パラメータsockfdのsocketをパラメータserv_に接続するためのaddrが指定したネットワークアドレス.クライアント接続に一般的に使用されます.
戻り値:
成功すると0が返され、失敗すると-1が返されます.
エラーコード:
1、EBADFパラメータsockfd非合法socket処理コード2、EFAULTパラメータserv_addrポインタはアクセスできないメモリ空間3を指し、ENOTSOCKパラメータsockfdはsocketではないファイル記述語である.4、EISCONNパラメータsockfdのsocketは既に結線状態5である、ETIMEDOUTが結線しようとする操作が制限時間を超えても応答しない.6、ENETUNREACHは指定のホストにパケットを転送できない.7、EAFNOSUPPORT sockaddr構造のsa_familyが正しくない.8、EALREADYソケットは遮断不能であり、かつ以前の配線操作がまだ完了していない.
例:
 	/*                ,        */  
    int ret = connect(client_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
    if (ret < 0) {
    	puts("client connect error!");
    	return 0;
    }

6.recv()受信データ
関数の定義:
int recv(int s, void *buf, int len, unsigned int flags);
recv()は、遠隔ホストから指定されたsocketを介して送信されたデータを受信し、パラメータbufによって指し示すメモリ空間にデータを格納するために使用され、パラメータlenは受信可能なデータの最大長である.
recv関数は一般的にブロックされています.しかし、ネットワークが切断されるなどの予期せぬ状況が発生すると、socketは閉じられ、resvはブロックされ続けます.この場合、ブロックされたsocketに対してsetsockoptを使用してsocketのタイムアウトを設定するのが一般的です.
flagsは一般的に0に設定されます.
を選択します.
説明
MSG_OOB
out-of-bandで送出するデータを受信する.
MSG_PEEK
返されたデータはシステム内で削除する、recv()を呼び出すと同じデータ内容が返される.
MSG_WAITALL
エラーや信号が発生しない限り、lenサイズのデータを強制的に受信してから戻る.
MSG_NOSIGNAL
この動作はSIGPIPE信号によって中断する戻り値が成功すると受信した文字数を返し、失敗して-1を返し、エラーの原因はerrnoに格納.
エラーコード:
1.EBADFパラメータsの非合法なsocket処理コード2.EFAULTパラメータにはアクセスできないメモリ領域を指すポインタがある.ENOTSOCKパラメータsはファイル記述語であり、socketではない.4.EINTRは信号によって中断する.EAGAINこの動作はプロセスを遮断するが、パラメータsのsocketは遮断できない6である.ENOBUFSシステムのバッファメモリが不足している.7.ENOMEMコアメモリ不足8.EINVALがシステム呼び出しに伝達するパラメータが正しくない.
例:
    //        
    char buf[1024];  //          
    int len;
    while ((len = recv(args_p->client_socketfd, buf, 1024, 0)) > 0) {  
        buf[len] = '\0';  
        printf("%s
", buf); if (send(args_p->client_socketfd, buf, len, 0) < 0) { perror("write"); } }

7.send()転送データ
関数の定義:
int send(int s, const void * msg, int len, unsigned int falgs);

send()は、指定するsocketから相手ホストにデータを転送するために使用される.パラメータsは接続が確立されたsocketである.パラメータmsgは接続しようとするデータの内容を指し、パラメータlenはデータ長である.パラメータflagsは一般的に0に設定されます.
戻り値:
成功すると実際に転送された文字数が返され、失敗すると-1が返されます.
エラーコード:
1.EBADFパラメータsの非合法的なsocket処理コード.2.EFAULTパラメータのポインタがアクセスできないメモリ領域を指す.ENOTSOCKパラメータsはファイル記述語であり、socketではない.4.EINTRは信号によって中断する.5.EAGAINこの操作はプロセスを遮断するが、パラメータsのsocketは遮断できない.6.ENOBUFSシステムのバッファメモリ不足7.ENOMEMコアメモリ不足8.EINVALがシステム呼び出しに伝達するパラメータが正しくない.
例:
    //      
    char * msg = "Welcome to My socket";
    int size = send(args_p->client_socketfd, msg, strlen(msg), 0);

8.shutdown()socketを閉じる
関数の定義:
int shutdown(int s, int how);
shutdown()は、パラメータsによって指定されたsocket配線を終了するために使用される.
howパラメータ:
how=0は読み出し動作を終了する.how=1転送終了how=2読み出しおよび転送終了
エラーコード:
1、EBADFパラメータsは有効なsocket処理コード2ではなく、ENOTSOCKパラメータsはファイル記述語であり、非socket 3、ENOTCONパラメータsが指定したsocketは接続されていない
例:
shutdown(server_socketfd, 2); //  socket