Let's make a program whose both a server and a client send a data.
one data from the client to the server is "client"s address(IP+port #)
and the other data is a time information from a server to a client.
We need to take a look at the accept function carefully.
If accept method has a second parameter and third parameter, it will save struct sockaddr inside.
This is a server side source code
Server.c
#include <sys/types.h> // 리눅스system call 관련헤더
#include <sys/socket.h> // 리눅스소켓헤더
#include <arpa/inet.h> // 인터넷관련헤더들
#include <stdio.h> // 표준입출력라이브러리
#include <stdlib.h> // strcmp 등을활용하기위한해더
int main(void) // 메인함수시작
{
struct sockaddr_in local; // server 주소정보를가질구조체선언
struct sockaddr_in client; // client에게보내줄구조체선언
int csize; // accept함수3번째인자에들어갈구조체의길이변수
int s; int s1; int rc; // s는socket() 리턴, s1은accept() 리턴rc는recv() 리턴값으로사용된다.
local.sin_family = AF_INET; // 우리가사용하는Internet을의미한다.
local.sin_port = htons(5300); // port#는5300으로예약되어있다.
local.sin_addr.s_addr = htonl(INADDR_ANY); // 어떤client든지다받겠다는의미이다.
char getTime[255]; // client로부터시간을받을데이터선언
printf("\n\nA server has been started, the port number is reserved as 5300\n");
// 서버시작메세지출력
s = socket(PF_INET, SOCK_STREAM, 0); // TCP를위한소켓생성
if(s<0){ // 소켓생성실패시
perror("socket call failed"); // 메세지를출력하고
exit(1); // 프로그램종료
} // if문의끝
rc = bind(s, (struct sockaddr *)&local, sizeof(local)); // port#와IP를연계시켜준다.
if(rc<0){ // Bind가실패하면
perror("bind call failure"); // 메세지를출력후
exit(1); // 종료한다.
} // if문의끝
printf("A server is waintg for a client request\n"); // client를기다린다는메세지를출력
rc = listen(s,5); // 5개의queue를생성한한다.
if(rc){ // 만약listen이실패하면
perror("listen call failed"); // 메세지를출력후
exit(1); // 프로그램을종료한다.
} // if문의끝
csize = sizeof(client); // csize는sockaddr 구조체크기를나타낸다
s1= accept(s,(struct sockaddr*)&client ,&csize); // 2번째인자는client 주소를받을구조체, 3번째는그구조체크기를명시
// 이후우리는client 주소에대한정보를알수있다.
printf("Conntection established!\n"); // 연결성공이라는메세지추력
if(s1<0){ // 만약accept가실패한다면
perror("accept call failed"); // 메세지를출력후
exit(1); // 프로그램을종료한다.
} // if문의끝
rc = recv(s1,getTime ,sizeof(getTime), 0); // client로부터시간을받는다.
if(rc<=0){ // 만약실패한다면
perror("recv call failed"); // 메세지를출력후
exit(1); // 프로그램을종료한다.
} // if문의 끝
printf("------Current time from client : %s ----------\n", getTime);
// 현재시간을출력한다.
printf("A server will send a client's IP address \n");
// client의주소를보낸다는메세지출력
rc = send(s1, &client , sizeof(client), 0); // client로자료를보낸다.
if(rc <= 0) // 만약send가실패하면
{ // if문시작
perror("send call failed"); // 메세지를출력후
exit(0); // 프로그램을종료한다.
} // if문의끝
printf("The server will be closed soon \n\n"); // 서버를종료한다는메세지
rc = close(s1); // close함수호출
if(rc < 0) // 만약실패하면
{
perror("close failed"); // 메세지를출력하고
exit(0); // 종료한다.
}
rc= close(s); // socket() 또한종료한다.
if(rc <0) // 만약실패하면
{
perror("close socket failed"); // 메세지를출력후
exit(0); // 프로그램을종료한다.
}
exit(0); // 성공하면프로그램을종료한다.
}
Client side.
#include <sys/types.h> // 리눅스system call 관련헤더
#include <sys/socket.h> // 리눅스소켓헤더
#include <arpa/inet.h> // 인터넷관련헤더들
#include <stdio.h> // 표준입출력라이브러리
#include <stdlib.h> // strcmp 등을활용하기위한해더
#include <time.h> // 현재시간을받기위해필요한헤더
int main(char argc, char *args[]) // 메인함수는인자를받기위해서parameter를설정하였다.
{
struct tm *timeinfo; // 시간을저장할구조체
time_t rawtime; // rawtime을이용해서시간을구할것이다.
struct sockaddr_in clientAddress; // 서버로부터받을데이터의구조체
struct sockaddr_in peer; // socket 생성시필요한구조체
int s; int rc; // s는socket descriptor로rc는flag 및받는데이터크기변수로사용
if(argc != 3){ // 만약서버주소와, port#를입력하지않았다면
printf("Usage : client.out serverIPaddress serverPort#"); // 사용법을알려주고
printf("Example : client.out 127.0.0.1 5300\n"); // 예를들어준다.
exit(1); // 그리고종료한다.
} // if문의끝
peer.sin_family = AF_INET; // Internet을위한'군'
peer.sin_addr.s_addr = inet_addr(args[1]); // argument를2진수형태의ip로바꾼후저장한다.
peer.sin_port = htons(atoi(args[2])); // port번호역시int형으로바꾼후시스템방식으로맞춘다.
memset(&peer.sin_zero,0,sizeof(peer.sinzero)); // sin_zero를모두0으로만든다.
time(&rawtime); // time을호출해서1960년이후초를받고
timeinfo = localtime(&rawtime); // rawtime을이용해서local 시간을받고
mktime(timeinfo); // 연,월,일,시,분,초형태로바꿔준다.
char currentTime[255]; // 시간정보를currentTime으로바꿔준다.
sprintf(currentTime, "Date -> %dyr - %dm - %dd time -> %dh:%dm:%ds",
timeinfo->tm_year+1900, timeinfo->tm_mon,
timeinfo->tm_mday, timeinfo->tm_hour,
timeinfo->tm_min, timeinfo->tm_sec);
// 구조체를string에대입한다. 연-월-일-시-분-초순이다.
printf("\n\nA client program has been started\n"); // 프로그램이시작됐음을알리는메세지
s = socket(PF_INET,SOCK_STREAM,0); // TCP 소켓을생성한다.
if(s<0){ // 소켓생성실패시
perror("socket call failed"); // 메세지를출력하고
exit(1); // 프로그램종료
} / if문의끝
rc = connect(s, (struct sockaddr *)&peer, sizeof(peer)); // 서버와연결한다.
if(rc){ // 연결이실패하면
perror("Connect call failed"); // 오류메세지출력후
exit(1); // 프로그램을종료한다.
} // if문의끝
printf("A client has been connected to the server\n"); // 성공하면이메세지를뿌려준다.
rc = send(s,currentTime , sizeof(currentTime), 0); // 그리고현재시간을서버에게보낸다.
if(rc <= 0){ // 만약보내는것이실패하면
perror("send call failed"); // 실패한다는메세지를보낸후
exit(1); // 나간다.
} // if문의끝
printf("A client sent a current time to the server\n"); // 전송이성공적으로됏으면이메세지를출력한다.
rc = recv(s,&clientAddress,sizeof(clientAddress),0); // 전송후서버로부터메세지를받는다.
// 2번째인자를보면수신을구조체로한다
if(rc<=0) // 전송이실패했을경우
perror("recv call failed"); // 메세지를출력한다.
else{ // 전송이성공했으면
printf("------- client IP address received from server : %s ----------- \n", inet_ntoa(clientAddress.sin_addr));
printf("-------client port number received from server : %d -----------\n", htons(clientAddress.sin_port));
} // 받은구조체를알맞게변환하게출력한다.
printf("The client will be closed \n\n"); // 데이터를받은후client는종료한다.
if(close(s)<0){ // 종료가비정상적이라면
perror("closing socket failed"); // 메세지를출력후
exit(0); // 프로그램을종료한다.
} // if문의끝
exit(0); // close가정상적이면다시종료한다.
}
'Programming > Network Programming' 카테고리의 다른 글
TCP packet and ICMP packet analysis (0) | 2011.10.28 |
---|---|
.. no regret.. (0) | 2011.10.26 |
The example of one server that sends a client ID (0) | 2011.10.15 |
get client IPadrress in server side (0) | 2011.10.10 |
Reference for unix socket api (0) | 2011.09.29 |