平台:win7 64bits / VC6++
语言:C++
函数介绍
int WSAStartup(
WORDwVersionRequested,
LPWSADATAlpWSAData
);
wVersionRequested:参数用于指定准备加载的Winsock库的版本。高位字节指定所需要的Winsock库的副版本,而低位字节则是主版本。由于需要返回WORDstruct,所以使用了
WORD MAKEWORD( BYTE bLow, BYTE bHigh ); 这个函数就是返回WORD structbLow返回低位字节,bHigh返回高位字节。
wVersionRequested = MAKEWORD(2,2);
lpWSAData:参数是指向WSADATA结构的指针,WSAStartup用其加载的库版本有关的信息填在这里:[out] Pointer to theWSADATA data structure that is to receive details of the Windows Sockets implementation. [out]是只这个参数作为函数的返回值
//////////////////////////////////////////////////////alt+F8可以自动调整代码格式
WSAData
typedef struct WSAData {
WORD wVersion; //
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
} WSADATA, *LPWSADATA;
///////////////////////////////////////////////////////////////
SOCKET socket( int af, inttype, intprotocol );
af:
type:[in] Type specification for the new socket. 只能用SOCK_STREAM(流式套接字)与SOCK_DGRAM(数据报套接字)
返回值SOCKET:返回一个描述符(类似于句柄),一个SOCKET类型的描述符。如果调用失败,就会返回一个INVALID_SOCKET,错误信息可以通过WSAGetLastError()函数返回。
///////////////////////////////////////////////////////////////
int bind( SOCKET s, //[in] Descriptor identifying an unbound socket. 指定要bind的套接字
const struct sockaddr FAR *name, //[in] Address to assign to the socket from theSOCKADDR structure制定了该套接字的本地地址信息,是指向sockaddr结构体的指针变量,由于该地址结构是为所有的地址家族准备的,这个结构可能随所用的网络协议不同而不同,所以要用第三个参数指定该地址结构的长度。
int namelen //第二个参数的长度,可以用sizeof来获得。
);
struct sockaddr{
u_short sa_family; //指向该地址家族,这里必须设置为AF_INET
char sa_data[14]; //要求一块内存分配区,起到占位作用,该区域中指定与协议相关的具体地址信息。在TCP/IP中,我们可以 用sockaddr_in来代替sockaddr,以方便我们填写地址信息
};
struct sockaddr_in{
short sin_family;//addr family AF_INET
unsigned short sin_port; // PORT
struct in_addr sin_addr; //ip ADDRS 一般设置为INADDR_ANY,如果不这么设置,需要使用inet_addr()函数。
char sin_zero[8]; //一个填充数字,使得 sockaddr与sockaddr_in长度一样
};
在上面结构体里,除了sin_family可以不使用网络字节序,其他的都需要转换,需用用到htonl与htons函数。hontl 传入与返回的是u_long,htons传入与返回的是u_short,所以转换端口是honts(6000),因为端口是两个字节。
///////////////////////////////////////////////////////
int listen(
SOCKET s, //创建的socket描述符
int backlog //可以监听的客户端的数字
);
SOCKET accept(
SOCKET s, //处于监听状态的套接字,就是服务器的套接字
struct sockaddr FAR* addr, //这是一个buffer,保存了客户端的IP信息和PORT信息,在使用之前,必须先声明一个地址对象,SOCKADDR_IN addrClient;
int FAR * addrlen //第二参数的长度 int len = sizeof (addrClient);
);
accept会返回一个新的socket套接字描述符,这个新的套接字就可以和服务器的socket进行通信了。
/////////////////////////////////////////////////////////////
int send(
SOCKET s, //accept新建立的socket
const char FAR* buf, // buffer,保存了想要传输的数据
int len, //传输数据的长度
int flag //设定flag 可以影响send函数的调用形式。一般设置为0
);
send(sockConn,sendBuf,strlen(sendBuf)+1,0);strlen(sendBuf)+1是因为我们想要传输的string最后有一个“\0“字符,在接收端,可以给字符串加一个结尾符号。
sprintf()函数,可以把特定的数据格式化到一个buffer中间去。 sprintf(sendBuf,"Welcome %s to http://www.sina.com", inet_ntoa(addrClient.sin_addr));
将Welcome %s to http://www.sina.com"格式化到sendBuf中间去,但是地址是string.IP地址嘛。所以门后面必须加addrClient.sin_addr...inet_ntoa()函数将addrClient.sin_addr
转换为点分十进制的字符串。
////////////////////////////////////////////////////////////
int recv( SOCKET s, char FAR *buf, int len, int flags );
第一个参数是建立连接后的套接字 第二个参数是一个接收数据的buffer,第三个参数数据的长度,,第四个是flags,通常设置为0.
closesocket(sockConn); //释放accept建立的socket,释放资源。就是在数据传输后。。。而WSACleanUp()是终止winsock库的使用,这之前需要释放服务器的socket。
在包含了Winsock2.h头文件之后,还需要连接一个库文件。
下面是介绍怎么连接库文件。
project->setings->link 然后再 Object/Library modules:框中,选到最后,添加 ws2_32.lib ->OK
服务器的代码
//Service
#include <IOSTREAM>
#include <Winsock2.h>
#include <stdio.h>
using namespace std;
void main()
{
//load socket lib. Use WSAStartup()
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 ) {
/
WSACleanup( );
return;
}
/* The WinSock DLL is acceptable. Proceed. */
//create socket.use socket();
SOCKET sockSrv = socket(AF_INET,SOCK_STREAM,0);
if (sockSrv == INVALID_SOCKET)
{
cout<<"socket create error!"<<endl;
int errCode = WSAGetLastError();
cout<<errCode<<endl;
WSACleanup( );
return;
}
//bind the socket to local addr. use bind();
//fist,set the IP and PORT.
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);// any IP addr.
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
// addrSrv.sin_zero = NULL;
//second,use bind();
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
//listen();
if ( 0==listen(sockSrv,5))
{
printf("socket listening...\n");
}
//accept()
SOCKADDR_IN addrClient;
int len = sizeof(addrClient);
while (1)
{
SOCKET sockConn = accept(sockSrv,(SOCKADDR*)&addrClient,&len);
char sendBuf[100];
sprintf(sendBuf,"Welcome %s to http://www.sina.com", inet_ntoa(addrClient.sin_addr));
send(sockConn,sendBuf,strlen(sendBuf)+1,0);//strlen(sendBuf)+1,because,when we got the string
char recvBuf[100];
recv(sockConn,recvBuf,100,0);
printf("%s\n",recvBuf);
closesocket(sockConn);
}
}