服务器端:
typedef unsigned short WORD
1.得到Socket版本号
WORD MAKEWORD(BYTE bLow,BYTE bHigh);
2.启动Socket,为Socket做准备
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
使用Socket的程序在使用Socket之前必须调用WSAStartup函数。
该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节指明副版本、低位字节指明主版本;
操作系统利用第二个参数返回请求的Socket的版本信息。
当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库,
然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的其它Socket
函数了。该函数执行成功后返回0。
3.释放系统资源
int WSACleanup (void);
应用程序在完成对请求的Socket库的使用后,要调用WSACleanup函数来解除与Socket库的绑定并
且释放Socket库所占用的系统资源。
4.建立Socket
SOCKET socket(int af, int type, int protocol);
应用程序调用socket函数来创建一个能够进行网络通信的套接字。
第一个参数指定应用程序使用的通信协议的协议族,af一般置为AF_INET;
第二个参数type为协议的Socket类型,常用的有3种:SOCK_STREAM、SOCK_DGRAM和SOCK_RAW。
SOCK_STREAM对应于TCP。
SOCK_DGRAM对应于UDP。
SOCK_RAW称为原始Socket,可以读写ICMP、IGMP、IP报文。前两种类型使用得最多。
第三个参数protocol指定所使用的协议。对于SOCK_STREAM、SOCK_DGRAM两种类型的Socket,该参
数为0,对于原始Socket才需要指定具体的协议。
接口用例如下:
SOCKET ServerSocket;
ServerSocket = socket(AF_INET,SOCK_STREAM,0);
5.清除Socket
int closesocket(SOCKET ServerSocket);
closesocket函数用来关闭一个描述符为ServerSocket套接字。
6.bind
int bind(SOCKET ServerSocket, const struct sockaddr FAR *name, int namelen);
当创建了一个Socket以后,套接字数据结构中有一个默认的IP地址和默认的端口号。一个服务程序
必须调用bind函数来给其绑定一个IP地址和一个特定的端口号。客户程序一般不必调用bind函数来为其Socket绑定IP地址和端口号。
该函数的第一个参数指定待绑定的Socket描述符;第二个参数指定一个sockaddr结构,其结构是:
struct sockaddr
{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
}
其中sin_family置AF_INET;sin_port指明端口号;sin_addr结构体中只有一个唯一的字段s_addr,表示IP地址,该字段是一个整数,
一般用函数inet_addr()把字符串形式的IP地址转换成unsigned long型的整数值后再置给s_addr。有的服务器是多宿主机,至少有两个网卡,
那么运行在这样的服务器上的服务程序在为其Socket绑定IP地址时可以把htonl(INADDR_ANY)置给s_addr,这样做的好处是不论哪个网段上
的客户程序都能与该服务程序通信.
如果只给运行在多宿主机上的服务程序的Socket绑定一个固定的IP地址,那么就只有与该IP地址处于同一个网段上的客户程序才能与该服务程序通信。
我们用0来填充sin_zero数组,目的是让sockaddr_in结构的大小与sockaddr结构的大小一致。下面是一个bind函数调用的例子:
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8888);
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(ServerSocket,(struct sockaddr *)&saddr,sizeof(saddr));
7.listen
int listen( SOCKET ServerSocket, int backlog );
服务程序可以调用listen函数使其流套接字ServerSocket处于监听状态。处于监听状态的流套接字ServerSocket将维护一个客户连接请求队列,
该队列最多容纳backlog个客户连接请求。假如该函数执行成功,则返回0;如果执行失败,则返回SOCKET_ERROR。
8.accept
SOCKET accept(SOCKET ServerSocket, struct sockaddr FAR *addr, int FAR *addrlen);
服务程序通过accept()得到一个新的套接字,这个新的套接字是服务端和客户端通信的通道.如果连接成功,就返回新创建
的套接字的描述符,以后与客户端套接字交换数据的就是新创建的套接字;如果失败就返回INVALID_SOCKET。
该函数的第一个参数指定处于监听状态的流套接字;操作系统利用第二个参数来返回新创建的套接字的地址结构;操作系统
利用第三个参数来返回新创建的套接字的地址结构的长度。下面是一个调用accept的例子:
struct sockaddr_in NewSocketAddr;
SOCKET NewSocket;
int NewAddrLen;
addrlen=sizeof(NewSocketAddr);
NewSocket =accept(ServerSocket,(struct sockaddr *)&NewSocketAddr,&NewSocketAddr);
9.recv
int recv(SOCKET NewSocket, char FAR *buf, int len, int flags);
不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数的第一个参数指定接收端套接字描述符;
第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;第三个参数指明buf的长度;第四个参数一般置0。
注:所有和发送及接收数据相关的缓冲区(buffer)都是char类型(一个char代表一个Byte),这样无论是二进制数据或者是字
符串文本都可以被缓冲区所容纳。
10.send
int send(SOCKET NewSocket,const char FAR *buf, int len,int flags);
不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,
而服务器则通常用send函数来向客户程序发送应答。该函数的第一个参数指定发送端套接字描述符;第二个参数指明一个存放应用
程序要发送数据的缓冲区;第三个参数指明实际要发送的数据的字节数;第四个参数一般置0。
注:所有和发送及接收数据相关的缓冲区(buffer)都是char类型(一个char代表一个Byte),这样无论是二进制数据或者是字
符串文本都可以被缓冲区所容纳。
客户端:
1.得到Socket版本号
WORD MAKEWORD(BYTE bLow,BYTE bHigh);
2.启动Socket,为Socket做准备
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
使用Socket的程序在使用Socket之前必须调用WSAStartup函数。
该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节指明副版本、低位字节指明主版本;
操作系统利用第二个参数返回请求的Socket的版本信息。
当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库,
然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的其它Socket
函数了。该函数执行成功后返回0。
3.释放系统资源
int WSACleanup (void);
应用程序在完成对请求的Socket库的使用后,要调用WSACleanup函数来解除与Socket库的绑定并
且释放Socket库所占用的系统资源。
4.建立Socket
SOCKET socket(int af, int type, int protocol);
应用程序调用socket函数来创建一个能够进行网络通信的套接字。
第一个参数指定应用程序使用的通信协议的协议族,af一般置为AF_INET;
第二个参数type为协议的Socket类型,常用的有3种:SOCK_STREAM、SOCK_DGRAM和SOCK_RAW。
SOCK_STREAM对应于TCP。
SOCK_DGRAM对应于UDP。
SOCK_RAW称为原始Socket,可以读写ICMP、IGMP、IP报文。前两种类型使用得最多。
第三个参数protocol指定所使用的协议。对于SOCK_STREAM、SOCK_DGRAM两种类型的Socket,该参
数为0,对于原始Socket才需要指定具体的协议。
接口用例如下:
SOCKET ClientSocket;
ClientSocket = socket(AF_INET,SOCK_STREAM,0);
5.清除Socket
int closesocket(SOCKET ClientSocket);
closesocket函数用来关闭一个描述符为ClientSocket套接字。
6.connect
int connect(SOCKET ClientSocket, const struct sockaddr FAR *name, int namelen);
客户端调用connect与服务器进行连接. 如果连接成功,connect返回0;如果失败则返回SOCKET_ERROR。
下面是一个例子:
struct sockaddr_in daddr;
memset((void *)&daddr,0,sizeof(daddr));
daddr.sin_family=AF_INET;
daddr.sin_port=htons(8888);
daddr.sin_addr.s_addr= inet_addr("192.168.1.14");
connect(ClientSocket,(struct sockaddr *)&daddr,sizeof(daddr));
7.send
int send(SOCKET ClientSocket,const char FAR *buf, int len,int flags);
不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,
而服务器则通常用send函数来向客户程序发送应答。该函数的第一个参数指定发送端套接字描述符;第二个参数指明一个存放应用
程序要发送数据的缓冲区;第三个参数指明实际要发送的数据的字节数;第四个参数一般置0。
注:所有和发送及接收数据相关的缓冲区(buffer)都是char类型(一个char代表一个Byte),这样无论是二进制数据或者是字
符串文本都可以被缓冲区所容纳。
8.recv
int recv(SOCKET ClientSocket, char FAR *buf, int len, int flags);
不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数的第一个参数指定接收端套接字描述符;
第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;第三个参数指明buf的长度;第四个参数一般置0。
注:所有和发送及接收数据相关的缓冲区(buffer)都是char类型(一个char代表一个Byte),这样无论是二进制数据或者是字
符串文本都可以被缓冲区所容纳。
接口应用时序图
代码示例
/****************************************************************************************/
/* 服务器端 */
/****************************************************************************************/
void *SocketTaskCallback(void *arg)
{
WORD wVersionRequested;
WSADATA wsaData;
SOCKET sockconn;
SOCKADDR_IN socketadd;
SOCKADDR_IN sockclient;
char getData[RECEIVE_MAX_LENGTH];
char sendData[SEND_MAX_LENGTH];
int receive_len = 0;
int err;
int len;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
DEBUG("Start up fail.\n");
return NULL;
}
if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
{
WSACleanup();
DEBUG("Version check fail.\n");
return NULL;
}
// 建立套接字
socksrv = socket(AF_INET,SOCK_STREAM,0);
// 绑定
socketadd.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
socketadd.sin_family = AF_INET;
socketadd.sin_port = htons(port);
if( SOCKET_ERROR == bind(socksrv,(SOCKADDR*)&socketadd,sizeof(SOCKADDR)) )
{
DEBUG("bind err\n");
Mux_ClearSocket();
}
// 监听
if( SOCKET_ERROR == listen(socksrv,5) )
{
DEBUG("listen err");
Mux_ClearSocket();
}
while(!done)
{
// 连接套节字
sockconn = accept(socksrv,(SOCKADDR*)&sockclient,&len);
if(INVALID_SOCKET == sockconn )
{
DEBUG("accept err\n");
Mux_ClearSocket();
}
//接收
memset(getData, 0, RECEIVE_MAX_LENGTH);
receive_len = recv(sockconn,getData,RECEIVE_MAX_LENGTH,0);
Mux_IniFileUpdata(getData,receive_len);
DEBUG("%s\n",getData);
//发送
sprintf(sendData,"%s","update ok!");
if( SOCKET_ERROR == send(sockconn,sendData,strlen(sendData)+1,0) )
{
DEBUG("send err\n");
Mux_ClearSocket();
}
closesocket(sockconn);
}
return (void*)NULL;
}
/****************************************************************************************/
/* 客户端 */
/****************************************************************************************/
int SocketClientCode(int argc, const char **argv)
{
WORD wVersionRequested;
WSADATA wsaData;
SOCKET ClientSocket;
SOCKADDR_IN socketadd;
char getData[RECEIVE_MAX_LENGTH];
char sendData[SEND_MAX_LENGTH];
int SocketResult;
int receive_len;
int err,len;
//获取要发送的数据
memset(sendData, 0, SEND_MAX_LENGTH);
if (!doargs(argc, argv,sendData))
{
return ERR;
}
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
DEBUG("Start up fail.\n");
return ERR;
}
if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
{
WSACleanup();
DEBUG("Version check fail.\n");
return ERR;
}
// 建立套接字
ClientSocket = socket(AF_INET,SOCK_STREAM,0);
//连接套接字
socketadd.sin_family = AF_INET;
socketadd.sin_port = htons(port);
socketadd.sin_addr.S_un.S_addr = inet_addr("192.168.1.14");
len = sizeof(SOCKADDR);
SocketResult = connect(ClientSocket,(SOCKADDR*)&socketadd,len);
if(INVALID_SOCKET == SocketResult )
{
DEBUG("connect err\n");
Client_ClearSocket();
};
//发送
if( SOCKET_ERROR == send(ClientSocket,sendData,SEND_MAX_LENGTH,0) )
{
DEBUG("send err\n");
Client_ClearSocket();
}
else
{
//接收
memset(getData, 0, RECEIVE_MAX_LENGTH);
receive_len = recv(ClientSocket,getData,RECEIVE_MAX_LENGTH,0);
DEBUG("%s\n",getData);
hxxm_mesgparse_client(getData,receive_len);
}
closesocket(ClientSocket);
return OK;
}