TCP/IP地址家族统一的套接字地址结构定义如下:
struct sockaddr_in
{
short sin_family; //指定地址家族,即地址格式
unsigned short sin_port; //端口号码
struct in_addr sin_addr; //IP地址
char sin_zero[8]; //需要指定为0
}
sin_family 指定使用该套接字地址的地址家族。 这里必须设置为AF_INET,表示程序所使用的地址家族是TCP/IP;
sin_zero[8] 主要是为了与第一个版本的套接字地址结构大小相同而设置,实际使用时,将这8个字节设置为0即可。
sin_addr 表示32为的IP地址结构 结构定义如下:
struct in_addr
{
union
{
struct
{
u_char s_b1,s_b2,s_b3,s_b4;
} S_un_b; //用4个u_char字符描述IP地址
struct
{
u_short s_w1,s_w2;
} S_un_w; //用2个u_short类型描述IP地址
u_long S_addr;//用1个u_long类型描述IP地址
} S_un;
#define s_addr S_un.S_addr
};
通常,使用一个u_long类型的字符进行描述IP地址即可。
sockaddr_in addr;
addr.sin_addr.S_un.S_addr = inet_addr("218.6.132.5");
Socket 套接字编程中,传输数据的排列顺序以网络字节顺序和主机字节顺序为主。
数据在主机存储时,是以主机字节顺序存储的。
数据要通过网络发送,需要转换为网络字节顺序。否则会造成损坏。
网络字节是将重要的字节优先存储,而主机字节顺序则相反。
Winsock 中的网络字节和主机字节的转换函数
主机字节->网络字节
u_short htons(u_short hostshort); //u_short 类型的IP地址
u_long htonl(u_long hostlong); //u_long
unsigned long inet_addr(const char FAR* cp);//字符串IP
网络字节->主机字节
u_long ntohl(u_long hostlong);//u_long
u_short ntols(u_short hostshort);//u_short
char FAR* inet_ntoa(struct in_addr in);//字符串IP
具体使用:
sockaddr_in addrTo;
addrTo.sin_family=AF_INET;
addrTo.sin_port=htons(8900);
addrTo.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
char address[] = inet_ntoa(addrTo.sin_addr.S_un.S_addr);
Socket 相关函数
1.创建套接字
CSocket 类创建套接字是通过其构造函数创建的
CSocket :: CSocket();
创建CSocket对象
CSocket sock;
或
CSocket *sock;
sock = new CSocket;
2.绑定地址信息
如果套接字对象是服务器套接字,那么该套接字应该调用该类的函数Bind()将套接字对象与服务器地址信息绑定在一起。
BOOL Bind(const SOCKADDR* lpSockAddr,int nSockAddrLen);
lpSockAddr 地址结构
nSockAddrLen 地址结构长度
地址绑定成功后,还要调用函数Listen()在指定端口监听客户端的连接请求。 函数Listen()的原型如下:
BOOL Listen(int nConnectionBackLog = 5);
nContectionBackLog 表示套接字监听客户请求的最大数目。有效范围1~5。
具体调用
CSocket sock;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
addr.sin_addr.S_un.s_addr = inet_addr("127.0.0.1");
sock.Bind((SOCKADDR*)addr,sizeof(addr)); //绑定套接字的地址结构
sock.Listen(5);
3.连接服务器
客户端创建套接字成功后,调用函数Connect()向服务器发送连接请求。
BOOL Connect(const SOCKADDR* lpSockAddr,int nSockAddrLen);
lpSockAddr 连接的服务器地址结构
nSockAddrLen 服务器地址结构长度
具体调用:
CSocket sock;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
addr.sin_addr.S_un_S_addr = inet_addr("127.0.0.1");
sock.Connect((SOCKADDR*)addr,sizeof(addr));//连接服务器
4.数据交换
通过Send()和Receive()进行数据交换
函数原型
virtual int Send(const void lpBuf,int nBuflen,int nFlags = 0);
virtual int Receive(void* lpBuf,int nBuflen,int nFlags = 0);
lpBuf: 数据缓冲区地址
nBuflen:数据缓冲区的大小
nFlags : 数据发送或接收标志,一般情况都设置为0
...
char buff[] = 'a';
sock.Send(&buff,sizeof(buff),0);
sock.Receive(&buff,sizeof(buff),0);
5.关闭套接字对象
服务端和客户端的通信完成后,调用函数Close()将套接字对象关闭
sock.Close();
注意:CSocket类的头文件 afxsock.h 使用时,必须引入此文件
#include<afxsock.h>
服务器端代码:
// SocketSever.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib,"WS2_32.lib")
int main(int argc, char* argv[])
{
//1.用户初始化套接字库
WSADATA data; //定义WSADATA结构体对象
WORD w = MAKEWORD(2,0); //定义版本号
char sztext[] = "欢迎你\r\n"; //定义并初始化发送到客户端的字符数组
::WSAStartup(w,&data); //初始化套接字库
//2.创建套接字
SOCKET s,s1; //定义连接套接字和数据收发套接字句柄
s = ::socket(AF_INET,SOCK_STREAM,0); //创建TCP套接字
sockaddr_in addr,addr2; //定义套接字地址结构
int n = sizeof(addr2); //获取套接字地址结构大小
addr.sin_family = AF_INET;
addr.sin_port = htons(75);
addr.sin_addr.S_un.S_addr = INADDR_ANY;
//3.绑定地址信息及启动监听
::bind(s,(sockaddr*)&addr,sizeof(addr)); //绑定套接字
::listen(s,5);
printf("服务器已经启动 \r\n");
//4.监听及接收请求
while(true)
{
s1 = ::accept(s,(sockaddr*)&addr2,&n);//接收连接请求
if(s1!=NULL)
{
printf("%s 已经连接上\r\n",inet_ntoa(addr2.sin_addr));
::send(s1,sztext,sizeof(sztext),0);
}
//5.关闭套接字对象
::closesocket(s);
::closesocket(s1);
//6.释放套接字库
::WSACleanup();
if(getchar())
{
return 0;
}
else
{
::Sleep(100);
}
}
}
客户端代码:
// SocketClient.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib,"WS2_32.lib")
int main(int argc, char* argv[])
{
//1.用户初始化套接字库
WSADATA data; //定义WSADATA结构体对象
WORD w = MAKEWORD(2,0); //定义版本号
::WSAStartup(w,&data); //初始化套接字库
//2.创建套接字
SOCKET s; //定义连接套接字
char sztext[10] = {0};
s = ::socket(AF_INET,SOCK_STREAM,0); //创建TCP套接字
sockaddr_in addr; //定义套接字地址结构
addr.sin_family = AF_INET;
addr.sin_port = htons(75);
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
printf("客户端已经启动 \r\n");
//3.连接服务器
::connect(s,(sockaddr*)&addr,sizeof(addr));
//4.接收服务器消息
::recv(s,sztext,sizeof(sztext),0);
printf("%s \r\n",sztext);
//5.关闭套接字对象
::closesocket(s);
//6.释放套接字库
::WSACleanup();
if(getchar())
{
return 0;
}
else
{
::Sleep(100);
}
}