socketベース(c言語)

6655 ワード

selectの一般的なベースsocket接続を使用しないで、複数のクライアントに対する反応は順序があって、接続を確立する順序によって
1.サービス側socket 2を確立する.サービス側socketは新しいconnectionを確立するつもりで、acceptは3をブロックします.クライアントはsocketを確立し、クライアントconnectサービス端4.サービス側acceptは戻り、connnctionを確立しrecvにブロックし、データを受け入れる準備をする(いくつかのクライアントはいくつかのconnectionを履歴する).クライアントはsocketにデータ6を送信.サービス側のconnectionは、recvがデータを受信して戻ります.
一言でコードに合わないので、まずcで書きます.
server.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>

#define MAXLINE 4096

int main(int argc, char** argv)
{
    int    listenfd, connfd;
    struct sockaddr_in     servaddr;
    char    buff[4096];
    int     n;

    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
    printf("create socket error: %s(errno: %d)
",strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(6666); if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){ printf("bind socket error: %s(errno: %d)
",strerror(errno),errno); exit(0); } if( listen(listenfd, 10) == -1){ printf("listen socket error: %s(errno: %d)
",strerror(errno),errno); exit(0); } printf("======waiting for client's request======
"); while(1){ if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){ printf("accept socket error: %s(errno: %d)",strerror(errno),errno); continue; } n = recv(connfd, buff, MAXLINE, 0); buff[n] = '\0'; printf("recv msg from client: %s
", buff); close(connfd); } close(listenfd); }

client.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
    
#define MAXLINE 4096

int main(int argc, char** argv)
{   
    int    sockfd, n;
    char    recvline[4096], sendline[4096];
    struct sockaddr_in    servaddr;
    
    if( argc != 2){
    printf("usage: ./client <ipaddress>
"); exit(0); } if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ printf("create socket error: %s(errno: %d)
", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(6666); if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){ printf("inet_pton error for %s
",argv[1]); exit(0); } if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){ printf("connect error: %s(errno: %d)
",strerror(errno),errno); exit(0); } printf("send msg to server:
"); fgets(sendline, 4096, stdin); if( send(sockfd, sendline, strlen(sendline), 0) < 0) { printf("send msg error: %s(errno: %d)
", strerror(errno), errno); exit(0); } close(sockfd); exit(0); }

gcc server.c -o server
gcc client.c -o client
サーバ側のテスト:

[root@centos32 c]# ./server 
======waiting for client's request======


3つのクライアントを開いて観察
最初の

[root@centos32 c]# ./client  127.0.0.1
send msg to server: 


ここでは入力しない
-------------------------
2番目

[root@centos32 c]# ./client  127.0.0.1
send msg to server: 
hello this is 2222222222222
  

サーバ端が反応しないことを観察する
---------------------
3番目のクライアント:

[root@centos32 c]# ./client  127.0.0.1
send msg to server: 
hello this is 33333333
  

サーバ端が反応しないことを観察する
---------------
最初のクライアントへ

[root@centos32 c]# ./client  127.0.0.1
send msg to server: 
this is 111111111

車に戻って、
サービス・エンドの観察
を選択します.

[root@centos32 c]# ./server 
======waiting for client's request======
recv msg from client: hello this is 1111111111

recv msg from client: hello this is 2222222222222

recv msg from client: hello this is 33333333

サービス側が返す値は,クライアントがconnectionを開く順序で返す説明に従ってサービス側に接続を確立するとrecvにブロックされ,後のclientが先にデータを送信しても先に戻ることはないことが分かった.
どちらが先に送信したいかは先に返すselectなどを使う必要があります
selectなどがなければ、
ソケットはブロックされていて、
最初のクライアントが接続されたときにacceptがそこに着いて待っていましたが、最初のクライアントが反応してから2つが続きます.
サービス側が返すのも接続が確立された順序で返される
ソケットの構築過程を見てみましょう
合計4つのプロセスで、サービス側は2回ブロックされ、接続とメッセージの受信を待機します.
クライアントが接続を確立し、データを送信する2回のトリガサービス
-------------(1)-------------
サービス:
server側はまずsocketハンドルを確立する
listenfd = socket(AF_INET, SOCK_STREAM, 0)
バインドアドレス
bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)
傍受ソケット
listen(listenfd, 10)
接続ハンドルを確立し、
そしてブロック#############################################################
connfd =accept(listenfd, (struct sockaddr*)NULL, NULL)
に注意
------------(2)---------
クライアント:
ソケットハンドルの作成
sockfd = socket(AF_INET, SOCK_STREAM, 0)
このハンドルでリモートのアドレスに接続します
connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)
--------------(3)--------------
サービス側acceptのブロック戻り
n = recv(connfd, buff, MAXLINE, 0);
ブロックデータ
---------------(4)---
クライアント
ハンドル送信データ
send(sockfd, sendline, strlen(sendline), 0)
----------------(5)--------------
サービス:
メッセージrecvの受信
######################################################
このような普通のsocketでは順序の問題がありますが、
後ろのクライアントが先にデータを送信すると、server側は前のクライアントの反応を待たずに、直接後ろのクライアントの対応に戻ります.
select等の導入が必要
リファレンスhttp://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html