2012年3月18日 星期日

[Socket]Vc++ 2010

大四下修TCPIP課程,第一項作業為 寫一個關於socket的程式,參考http://www.powercam.cc/show.php?id=218  而修改出如下的code,
作業環境:win7 32bit
Compiler: VC++ 2010



以下為Server端:code

/////////////////////////////////////////////////////////

#ifndef _WINSOCK2API_
#endif
// Prevent inclusion of winsock.h
#ifdef _WINSOCKAPI_
#endif

// NOTE: If you use Windows Platform SDK, you should enable following definition:
// #define USING_WIN_PSDK

#if !defined(WIN32_LEAN_AND_MEAN) && (_WIN32_WINNT >= 0x0400) && !defined(USING_WIN_PSDK)
#include <windows.h>
#else
#include <winsock2.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma   comment   (lib, "WS2_32.lib ")

//#pragma comment(lib, "winsock.lib")
#define MAXLINE 1024    //buffer line


void main()
{

SOCKET serv_sd,cli_sd;
int cli_len,n;
char str[MAXLINE];

struct sockaddr_in          serv,cli;

WSADATA wsadata;

if(WSAStartup(0x101,(LPWSADATA) &wsadata) !=0 )  //要使用winsock API 必須先statrup
{
fprintf (stderr,"echo_serv:can;t use winsockDLL\n");
exit(1);
}
if ( (serv_sd = socket (AF_INET,SOCK_STREAM,0) ) == SOCKET_ERROR)
{
fprintf (stderr,"echo_serv:can't open TCP socket\n");
exit(1);
}

/////以上在建立socket


//以下在填入winsock struct 資訊
serv.sin_family              =AF_INET;
serv.sin_addr.s_addr         =0;        //0 為無強制server ip 給 winsock 決定
serv.sin_port                =htons(IPPORT_ECHO); //指定IPPort_echo 為echo port


//以下定義protocal
if (bind (serv_sd,(LPSOCKADDR)&serv,sizeof(serv))<0)
{
fprintf(stderr,"echo_serv :can't bind local address\n");
exit(1);
}

//以下為最多可以listen 5個request

if( listen (serv_sd,5)<0)
{
fprintf(stderr,"echo_serv:listen() error\n");
exit(1);
}

//以下為傳送接收


cli_len = sizeof(cli);

while(1)        
{
printf("echo_serv:waiting for client\n");
cli_sd=accept(serv_sd,(struct sockaddr *)&cli,&cli_len);//建立與client的連線
if(cli_sd==SOCKET_ERROR)    
{
fprintf(stderr,"echo_serv:accept() error\n");
closesocket(cli_sd);
}
else
{
while(1)
{
if( (n=recv(cli_sd,str,MAXLINE,0)) ==0)
{
fprintf(stderr,"echo_serv:connection closed\n");
break;
}else if (n==SOCKET_ERROR)
{
fprintf (stderr,"echo_serv:recv() error \n");
break;
}

str[n]='\0';
printf("echo_serv:%s",str); //顯示從client 傳來的字串

if(send(cli_sd,str,strlen(str),0) == SOCKET_ERROR)
{
fprintf(stderr,"echo_serv:connection closed\n");
break;
}

}//while
}//if
}

//結束 winsock DLL

closesocket(serv_sd);
closesocket(cli_sd);
WSACleanup();


}//main


/////////////////////////////////////////////////////////////////server端code結束



//////////////////////////////////////////////////////////////以下為client端

#ifndef _WINSOCK2API_
#endif
// Prevent inclusion of winsock.h
#ifdef _WINSOCKAPI_
#endif

// NOTE: If you use Windows Platform SDK, you should enable following definition:
// #define USING_WIN_PSDK

#if !defined(WIN32_LEAN_AND_MEAN) && (_WIN32_WINNT >= 0x0400) && !defined(USING_WIN_PSDK)
#include <windows.h>
#else
#include <winsock2.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma   comment   (lib, "WS2_32.lib ")

//#pragma comment(lib, "winsock.lib")
#define MAXLINE 1024    //buffer line

void main()
{
SOCKET sd;                        //socket 描述子
int n;
char str[MAXLINE];
struct sockaddr_in   serv;
WSADATA wsadata;

if(WSAStartup(0x101,(LPWSADATA) &wsadata) !=0 )  //要使用winsock API 必須先statrup
{
fprintf (stderr,"echo_serv:WSAStartup() fails\n");
exit(1);
}

printf("Please keyin server IP: ");   //輸入目標server的IP
fgets(str,MAXLINE,stdin);

serv.sin_family              =AF_INET;  //family  =  IPv4
serv.sin_addr.s_addr         =inet_addr(str); //IP 為剛剛輸入的
serv.sin_port                =htons(IPPORT_ECHO); //指定IPPort_echo 為echo port

//開啟TCP socket
if( (sd=socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
{
fprintf(stderr,"echo_cli:can't open tcp socket\n");
exit(1);
}

//try to connect server

if(connect(sd,(LPSOCKADDR) &serv,sizeof(serv)))
{
fprintf (stderr,"echo_cli:can't connect to server\n");
exit(1);
}

while(fgets(str,MAXLINE,stdin) !=NULL)   //要求使用者keyin字串
{
if(send(sd,str,strlen(str)+1,0) == SOCKET_ERROR)  //傳送字串看有無錯誤
{
fprintf(stderr,"echo_cli:send() error! \n");
break;
}
if ( (n=recv(sd,str,MAXLINE,0)) == 0)
{
fprintf(stderr,"echo_cli:connection closed\n");
break;
}else if(n==SOCKET_ERROR)  
{
fprintf(stderr,"echo_cli:recv() error!\n");
break;
}
else printf(str);       //若收回來也無錯誤則Print

}

closesocket(sd);
WSACleanup();


}//main

/////////////////////////////////////////////////////

備忘:對於原影片作者中的include各項會無法載入"winsock.h"所以上網查了許多的資料,最後用了上述的define方法終於解決了否則會顯示"無法辨析的外部符號.........."

但是上述code只能一個server對應一個client,若有其他client同時進入,則必須排隊在外等待,若要做到類似聊天室的功能,可能需要增加thread來監聽其他client,有待改進


                                                                                                                2012.3.18   ED







沒有留言:

張貼留言