ラベル c の投稿を表示しています。 すべての投稿を表示
ラベル c の投稿を表示しています。 すべての投稿を表示

2007年9月9日日曜日

UDP版echoサーバ







#include<stdio.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>


#define MAX 255

void exitWithError(char *message);


int main(int argc,char *argv[])
{
int sock;
struct sockaddr_in echoServAddr;
struct sockaddr_in echoCliAddr;
unsigned int cliAddrLen;
char echoBuffer[MAX];
unsigned short echoServPort;
int recvMsgSize;


if(argc != 2){
fprintf(stderr,"Usage %s <Port>\n,argv[0]");
exit (1);
}

echoServPort = atoi(argv[1]);


if((sock = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
exitWithError("socket() error\n");


memset(&echoServAddr,0,sizeof(echoServAddr));
echoServAddr.sin_family = AF_INET;
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
echoServAddr.sin_port = htons(echoServPort);


if(bind(sock,(struct sockaddr *)&echoServAddr,sizeof(echoServAddr)) < 0)
exitWithError("bind() error\n");


for(;;)
{
cliAddrLen = sizeof(echoCliAddr);

if((recvMsgSize = recvfrom(sock,echoBuffer,MAX,0,(struct sockaddr *)&echoCliAddr,&cliAddrLen)) < 0)
exitWithError("recvfrom() error\n");


printf("Handling: %s\n",inet_ntoa(echoCliAddr.sin_addr));

if(sendto(sock,echoBuffer,recvMsgSize,0,(struct sockaddr *)&echoCliAddr,sizeof(echoCliAddr)) != recvMsgSize)
exitWithError("sendto() bytes error\n");

}

}

void exitWithError(char *message)
{
printf("%s\n",message);
exit(1);
}





2007年9月7日金曜日

UDP版echoクライアント







#include<stdio.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

#define MAX 255

void exitWithError(char *message);

int main(int argc,char *argv[])
{
int sock;
struct sockaddr_in servAddr;
struct sockaddr_in fromAddr;
unsigned short servPort;
unsigned int fromSize;
char *echoString;
char *servIP;
char echoBuffer[MAX+1];
int echoStringLen;
int recvStringLen;



if(argc < 3){
fprintf(stderr,"Usage: %s <ServIP> <Word> [<Serv Port>]\n",argv[0]);
exit (1);
}

echoString = argv[2];
servIP = argv[1];


if((echoStringLen = strlen(echoString)) > MAX)
exitWithError("word is too long\n");


if(argc == 4)
servPort = atoi(argv[3]);
else
servPort = 7;


if((sock = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
exitWithError("sockt() error\n");

memset(&servAddr,0,sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr(servIP);
servAddr.sin_port = htons(servPort);


if(sendto(sock,echoString,echoStringLen,0,(struct sockaddr *) &servAddr,sizeof(servAddr)) != echoStringLen)
exitWithError("sendto() error\n");


fromSize = sizeof(fromAddr);


if((recvStringLen = recvfrom(sock,echoBuffer,MAX,0,(struct sockaddr *) &fromAddr,&fromSize)) != echoStringLen)
exitWithError("recvfrom() error\n");


if(servAddr.sin_addr.s_addr != fromAddr.sin_addr.s_addr)
{
fprintf(stderr,"recv from unkown host\n");
exit (1);
}

echoBuffer[recvStringLen] = '\0';
printf("Received: %s\n",echoBuffer);

close(sock);

return 0;
}

void exitWithError(char *message)
{
printf("%s\n",message);
exit (1);
}



コンパイルも通って実行もできるのに、なぜかエコーされてこないと思ったら


udpのエコーサーバが動いてませんでした。。。。


それで1時間ぐらい悩んでしまいました。





2007年9月4日火曜日

daytimeクライアント




#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<netdb.h>


#define RCVSIZE 1024

void exitError(char *message);


int main(int argc,char *argv[])
{
int sock;
char buffer[RCVSIZE];
char *servIP;
struct sockaddr_in sockaddr;
int bytes=0;

if(argc < 1)
{
fprintf(stderr,"Usage %s <servIP>\n",argv[0]);
exit (1);
}


servIP = argv[1];


if((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
exitError("socket() error\n");


memset(&sockaddr,0,sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr(servIP);
sockaddr.sin_port = htons(13);


if(connect(sock,(struct sockaddr *) &sockaddr,sizeof(sockaddr)) < 0)
exitError("connect error\n");

while(recv(sock,buffer,RCVSIZE,0) >= 1)
{
printf("%s",buffer);
}

close(sock);
}


void exitError(char *message)
{
printf("%s\n",message);
exit (1);
}





2007年9月3日月曜日

これまでのまとめ






クライアントの方は、



  • 1.socket()でソケットを作成する。

  • 2.connect()でサーバへ接続する。

  • 3.send()で送信、recv()で受信する。

  • 4.close()で接続を切断し、ソケットを破棄する。



サーバの方は、



  • 1.socket()でソケットを作成する。

  • 2.bind()でソケットにポート番号を割り当てる。

  • 3.listen()でソケットを接続待ちにする。

  • 4.accept()を呼び出してソケットを新しくつくる。

  • 5.recv()で受信、send()で送信する。

  • 6.close()で接続を切断、新しく作ったソケットを破棄する。






ソケット関連の関数のメモ3



CPUのバイトオーダの関係で送受信したバイトの順序がおかしくなるので、


送信する順序を統一する必要がある。そのために、送信前に変換する。





long int htonl(long int hostLong)


short int htons(short int hostShort)


ホストのバイトオーダからネットワークバイトオーダに変換する。





long int ntohl(long int netLong)


short int ntohs(short int netShort)


ホストのバイトオーダからネットワークバイトオーダに変換する。





2007年8月31日金曜日

echoサーバ




#include<stdio.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

#define MAX 5
#define RCVSIZE 32

void errorExit(char *message);
void Handling(int clntSocket);


int main(int argc,char *argv[])
{
int servSocket;
int clntSocket;
struct sockaddr_in echoServAddr;
struct sockaddr_in echoClntAddr;
unsigned short echoServPort;
unsigned int clntLen;

if(argc != 2){
fprintf(stderr,"Usage: %s <Port>\n",argv[0]);
exit(1);
}

echoServPort = atoi(argv[1]);

if((servSocket = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
errorExit("socket error\n");

memset(&echoServAddr,0,sizeof(echoServAddr));
echoServAddr.sin_family = AF_INET;
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
echoServAddr.sin_port = htons(echoServPort);

if(bind(servSocket,(struct sockaddr *) &echoServAddr,sizeof(echoServAddr)) < 0)
errorExit("bind error\n");

if(listen(servSocket,MAX) < 0)
errorExit("listen error\n");

for(;;){

clntLen = sizeof(echoClntAddr);

if((clntSocket = accept(servSocket,(struct sockaddr *) &echoClntAddr,&clntLen)) < 0)
errorExit("accept error\n");

printf("Handling client %s\n",inet_ntoa(echoClntAddr.sin_addr));

Handling(clntSocket);
}


}

void Handling(int clntSocket)
{
char echoBuffer[RCVSIZE];
int recvMesSize;


if((recvMesSize = recv(clntSocket,echoBuffer,RCVSIZE,0)) < 0)
errorExit("recv error\n");

while(recvMesSize > 0)
{
if(send(clntSocket,echoBuffer,recvMesSize,0) != recvMesSize)
errorExit("send error\n");

if((recvMesSize = recv(clntSocket,echoBuffer,RCVSIZE,0)) < 0)
errorExit("recv error\n");
}

close(clntSocket);
}



関数名、変数名を付けるセンスがないって気づいてしまった。。。。





socket関連の関数のメモ2



manページ書き写してるだけなんで気にしないでください。






  • man 2 bind


int bind(int sockfd,const struct *sockaddr,socklen_t addr_len)


サーバのソケットにローカルのアドレス等を割り当てる


sockfd


ソケットのディスクリプタ


*sockaddr


サーバのアドレス、ポート、アドレスファミリの構造体



addr_len


構造体のサイズ


戻り値は成功時に0、それ以外は-1







  • man 2 listen


int listen(int sockfd,int backlog)


ソケットを接続待ちの状態にする


sockfd


ソケットのディスクリプタ


backlog


同時接続最大数


戻り値は成功時に0、それ以外は-1












  • man 2 accept


int accept(int sockfd,struct *sockaddr,socklen_t *addrlen)


ソケットへの接続を受け付ける


sockfd


ソケットのディスクリプタ


*sockaddr


クライアントのアドレスが入る


*addrlen


sockaddrのサイズが入る


戻り値はアドレスのサイズ(バイト単位)









  • inet_ntoa()


ドット10進数のIPアドレスを32bit2進数に変換する。






  • inet_addr()


32bit2進数表記のIPアドレスをドット10進数に変換する。





2007年8月29日水曜日

socket関連の関数のメモ







  • man 2 socket


int socket(int domain,int type,int protocol)


ソケットを作って、そのソケットのディスクリプタを返す。


domain


プロトコルファミリの指定


PF_INET IPv4


PF_INET6 IPv6


などがある。とりあえず今のところは、PF_INETしか使わないと思う。


type


通信方法の指定


SOCK_STREAM


SOCK_DGRAM


などがある。色々とあるが、とりあえずこの2つしか使わないと思う。





protocol


そのソケットが利用するプロトコルを指定する。


戻り値は、ソケットのディスクリプタ、エラーの場合には-1









  • man 2 connect


int connect(int sockfd,const struct sockaddr *serv_addr,socklen_t addr_len)


ディスクリプタsockfdが参照するソケットを*serv_addrのアドレスに接続する。


sockfd


接続するソケットのディスクリプタ





*serv_addr


接続先のIPアドレス、ポート番号等を指定する。





addr


serv_addrのサイズを指定する。


socketlen_tとなっているが実際にはint。


戻り値


成功時は、0。失敗したときは、-1









  • man 2 send


ssize_t send(int s,const void *buf,size_t len,int flags)


ソケットにメッセージを送る。


s


ソケットのディスクリプタ


*buf


送信したいメッセージのポインタ


len


送信したいメッセージのサイズ


flags


send()が呼び出されたときのプログラムの振舞を決める。


man を読んでも良く理解できない。0でデフォルトになる。


戻り値


成功時は、送信したメッセージのサイズ。失敗したときは、-1







  • man 3 recv


ssize_t recv(int s,void *buf,size_t len,int flags)


s


ソケットのディスクリプタ


*buf


受信したメッセージを入れるバッファ


len


バッファのサイズ


flags


recv()が呼び出されたときのプログラムの振舞を決める。


man を読んでも良く理解できない。0でデフォルトになる。



戻り値


成功時は、受信したメッセージのサイズ。失敗したときは-1





echoクライアント




#include<stdio.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

#define RBUFFER 1024

void ExitError(char *message);

int main(int argc,char *argv[])
{
int sock;
struct sockaddr_in echoServAddr;
unsigned short echoServPort;
char *ServIP;
char *echoString;
char echoBuffer[RBUFFER];
unsigned int echoStringLen;
int byteRec;
int byteTotal;


if(argc < 3){
fprintf(stderr,"Usage %s <ServIP> <Word>\n",argv[0]);
exit(1);
}

ServIP = argv[1];
echoString = argv[2];
echoServPort = 7;

printf("send =%s\n",echoString);


if ((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
ExitError("Error socket");

memset(&echoServAddr,0,sizeof(echoServAddr));
echoServAddr.sin_family = AF_INET;
echoServAddr.sin_addr.s_addr = inet_addr(ServIP);
echoServAddr.sin_port = htons(echoServPort);


if(connect(sock,(struct sockaddr *) &echoServAddr,sizeof(echoServAddr)) < 0)
ExitError("Fail connect");

echoStringLen = strlen(echoString);


if(send(sock,echoString,echoStringLen,0) != echoStringLen)
ExitError("Fail send");

byteTotal = 0;
printf("Received=");

while(byteTotal != echoStringLen){
if((byteRec = recv(sock,echoBuffer,RBUFFER-1,0)) <= 0)

ExitError("recievesize error");

byteTotal += byteRec;
echoBuffer[byteRec] = '\0';
printf(echoBuffer);
}

printf("\n");

close(sock);

return 0;

}

void ExitError(char *message)
{
perror(message);
exit (1);
}