socketベース(c言語)
selectの一般的なベースsocket接続を使用しないで、複数のクライアントに対する反応は順序があって、接続を確立する順序によって
1.サービス側socket 2を確立する.サービス側socketは新しいconnectionを確立するつもりで、acceptは3をブロックします.クライアントはsocketを確立し、クライアントconnectサービス端4.サービス側acceptは戻り、connnctionを確立しrecvにブロックし、データを受け入れる準備をする(いくつかのクライアントはいくつかのconnectionを履歴する).クライアントはsocketにデータ6を送信.サービス側のconnectionは、recvがデータを受信して戻ります.
一言でコードに合わないので、まずcで書きます.
server.c
client.c
gcc server.c -o server
gcc client.c -o client
サーバ側のテスト:
3つのクライアントを開いて観察
最初の
ここでは入力しない
-------------------------
2番目
サーバ端が反応しないことを観察する
---------------------
3番目のクライアント:
サーバ端が反応しないことを観察する
---------------
最初のクライアントへ
車に戻って、
サービス・エンドの観察
を選択します.
サービス側が返す値は,クライアントが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
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