一、创建控制台服务端的步骤:
1.启动 WinSock DLL -------> WSAStartup
2.创建套接字 Socket
3.绑定套接字和本地IP bind
4.将套接字设置为监听模式 listen
5.接收客户端的请求产生连接套接字 accepte
1.第一步使用 WSAStartup 函数启动 WinSock DLL
WSAStartup Function: The WSAStartup function initiates use of the Winsock DLL by a process.
(1)必要条件 #include <Winsock2.h> , 动态链接添加 ws2_32.lib(链接器->输入->附加依赖项 中添加 .lib)
(2)WSAStartup 函数介绍:
int WSAStartup(
__in WORD wVersionRequested,// WORD-->unsigned short(两个字节 16位 0~65535)
__out LPWSADATA lpWSAData // 输出信息,有关信息存储在这个结构体中
);
//第一个参数: wVersionRequested:指定呼叫者(客户端)可以使用的Windows Socket 的最高版本,高位字节代表 副版本号,低位字节代表 主版本号
// 可以使用的版本号(1.0, 1.1, 2.0, 2.1, 2.2)
// Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h
//第二个参数: lpWSAData: 一个指向结构体 WSAData 的指针,结构体信息如下:
typedef struct WSAData {
WORD wVersion; // Windows Sockets specification 版本信息,高位字节 副版本,低位字节 主版本
WORD wHighVersion;// Ws2_32.dll 所能支持的 Windows Sockets specification 最高版本
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets; // 这个一般不用
unsigned short iMaxUdpDg; // 这个一般不用
char FAR *lpVendorInfo;
} WSADATA, *LPWSADATA;
2.使用 socket 函数 创建套接字,这一步创建的套接字用于监听
SOCKET WSAAPI socket(
__in int af,//The address family specification. 我们一般使用 AF_INET(指定IP规范为 IPV4)
__in int type,// 套接字规范 一般是用流式套接字 SOCK_STREAM
__in int protocol // 协议 如果设定为 0 ,表示根据套接字自动选择协议,可用的有 IPPROTO_TCP IPPROTO_UDP 等
);
3.使用 bind 函数将上面创建的套接字与本地IP和端口号进行绑定
The bind function associates a local address with a socket.
// bind函数将本地 IP 地址与一个套接字 socket 进行绑定
int bind(
__in SOCKET s,// 将被绑定的 socket
__in const struct sockaddr *name,//指向结构体 sockaddr 的指针
__in int namelen // 第二个参数中结构体的长度
);
struct sockaddr
{
u_short sa_family;
char sa_data[14];
};
sa_family:指定该地址家族,在这里必须使用 AF_INET(IPV4)
sa_data:仅仅是表示要求一块内存分配区,起到占位的作用,该区域中指定与协议相关的具体地址信息。由于实际要求的只
是内存区,所以对于不同的协议家族,用不同的结构来替换 sockaddr,除了 sa_family 外,sockaddr 是按网络字节顺序
表示的。在TCP/IP 中,我们可以用 sockaddr_in 结构替换 sockaddr,以方便我们填写地址信息。
struct sockaddr_in
{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sin_family:地址族,对于IP地址,sin_family 成员将一直是 AF_INET
sin_port:将要分配给套接字的端口,大于 1024
sin_addr:给出的是套接字的主机IP地址
sin_zero:只是一个填充数,使 sockaddr_in 结构和 sockaddr 结构的长度一样
如果 bind 函数调用成功,返回0,失败返回 SOCKET_ERROR
错误信息可以通过WSAGetLastError 函数返回
4.监听 listen
int listen(
__in SOCKET s,
__in int backlog
);
监听成功返回 0
5.accepte 接收请求
6.send 发送消息
1.启动 WinSock DLL -------> WSAStartup
2.创建套接字 Socket
3.绑定套接字和本地IP bind
4.将套接字设置为监听模式 listen
5.接收客户端的请求产生连接套接字 accepte
6.发送消息给客户端 send
7.接收客户端发送过来的消息 recv---->(关闭连接套接字 closesocket)
二、创建客户端步骤
1.启动 WinSock DLL -------> WSAStartup
2.创建套接字 Socket
3.建立连接 connect
4.接收消息 recv 发送消息 send
5.关闭套接字 closesocket
6.终止对套接字库的使用 WSACleanup();
1.第一步使用 WSAStartup 函数启动 WinSock DLL
WSAStartup Function: The WSAStartup function initiates use of the Winsock DLL by a process.
(1)必要条件 #include <Winsock2.h> , 动态链接添加 ws2_32.lib(链接器->输入->附加依赖项 中添加 .lib)
(2)WSAStartup 函数介绍:
int WSAStartup(
__in WORD wVersionRequested,// WORD-->unsigned short(两个字节 16位 0~65535)
__out LPWSADATA lpWSAData // 输出信息,有关信息存储在这个结构体中
);
//第一个参数: wVersionRequested:指定呼叫者(客户端)可以使用的Windows Socket 的最高版本,高位字节代表 副版本号,低位字节代表 主版本号
// 可以使用的版本号(1.0, 1.1, 2.0, 2.1, 2.2)
// Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h
//第二个参数: lpWSAData: 一个指向结构体 WSAData 的指针,结构体信息如下:
typedef struct WSAData {
WORD wVersion; // Windows Sockets specification 版本信息,高位字节 副版本,低位字节 主版本
WORD wHighVersion;// Ws2_32.dll 所能支持的 Windows Sockets specification 最高版本
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets; // 这个一般不用
unsigned short iMaxUdpDg; // 这个一般不用
char FAR *lpVendorInfo;
} WSADATA, *LPWSADATA;
2.使用 socket 函数 创建套接字,这一步创建的套接字用于监听
SOCKET WSAAPI socket(
__in int af,//The address family specification. 我们一般使用 AF_INET(指定IP规范为 IPV4)
__in int type,// 套接字规范 一般是用流式套接字 SOCK_STREAM
__in int protocol // 协议 如果设定为 0 ,表示根据套接字自动选择协议,可用的有 IPPROTO_TCP IPPROTO_UDP 等
);
3.使用 bind 函数将上面创建的套接字与本地IP和端口号进行绑定
The bind function associates a local address with a socket.
// bind函数将本地 IP 地址与一个套接字 socket 进行绑定
int bind(
__in SOCKET s,// 将被绑定的 socket
__in const struct sockaddr *name,//指向结构体 sockaddr 的指针
__in int namelen // 第二个参数中结构体的长度
);
struct sockaddr
{
u_short sa_family;
char sa_data[14];
};
sa_family:指定该地址家族,在这里必须使用 AF_INET(IPV4)
sa_data:仅仅是表示要求一块内存分配区,起到占位的作用,该区域中指定与协议相关的具体地址信息。由于实际要求的只
是内存区,所以对于不同的协议家族,用不同的结构来替换 sockaddr,除了 sa_family 外,sockaddr 是按网络字节顺序
表示的。在TCP/IP 中,我们可以用 sockaddr_in 结构替换 sockaddr,以方便我们填写地址信息。
struct sockaddr_in
{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sin_family:地址族,对于IP地址,sin_family 成员将一直是 AF_INET
sin_port:将要分配给套接字的端口,大于 1024
sin_addr:给出的是套接字的主机IP地址
sin_zero:只是一个填充数,使 sockaddr_in 结构和 sockaddr 结构的长度一样
如果 bind 函数调用成功,返回0,失败返回 SOCKET_ERROR
错误信息可以通过WSAGetLastError 函数返回
4.监听 listen
int listen(
__in SOCKET s,
__in int backlog
);
监听成功返回 0
5.accepte 接收请求
6.send 发送消息
7.recv 接收消息
#include
#include
void main()
{
//---------------------------------------------------------------------------------------------------------------
// 使用函数 WSAStartup 启动 WinSock DLL
//---------------------------------------------------------------------------------------------------------------
WORD wVersionRequested;
WSADATA wsaData; // 创建一个 WSADATA 结构体的变量, 这个变量是用来接收
// Windows Sockets implementation. 的信息的
int err = 0; // 用来接收错误信息的
/*Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(1, 1); // Window Socket application 1.1
err = WSAStartup(wVersionRequested, &wsaData); // 创建成功返回 0
// 如果 启动 WinSock DLL 不成功
if (err != 0)
{
return;
}
// 如果版本信息与设置的不相同
if (HIBYTE(wsaData.wVersion) != 1 || LOBYTE(wsaData.wVersion) != 1)
{
return;
}
//---------------------------------------------------------------------------------------------------------------
// 使用函数 socket 创建套接字 , 然后使用函数 bind 将套接字与本地IP和端口进行
// 绑定,使用 listen 监听
//---------------------------------------------------------------------------------------------------------------
SOCKET socSrv = socket(AF_INET,SOCK_STREAM,0); // 准备用来监听的套接字
// 绑定套接字,设置地址族信息
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//htonl()将主机数转换成无
//符号长整形的网络字节顺序
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000); // 端口号
// 绑定 socket
bind(socSrv,(SOCKADDR *)&addrSrv,sizeof(SOCKADDR));
// 监听
listen(socSrv,5); // 意思是开启监听且最多可以监听5个
SOCKADDR_IN addrClient; // 用来存储连接上的客户端的地址族信息
int len = sizeof(SOCKADDR);
// accept 接收请求
while (1)
{
// 创建连接套接字
SOCKET sockConn = accept(socSrv, (SOCKADDR *)&addrClient, &len);
// 发送数据
char sendBuf[100];
sprintf(sendBuf,"客户端的地址:%s",inet_ntoa(addrClient.sin_addr));
send(sockConn,sendBuf,strlen(sendBuf) + 1, 0);
// 接收数据
char recvBuff[100];
recv(sockConn,recvBuff,100,0);
printf("%s\n",recv);
// 关闭连接套接字
closesocket(sockConn);
}
}
//---------------------------------------------------------------------------
// 客户端程序
#include
#include
#include
void main() { //--------------------------------------------------------------------------------------------------------------- // 使用函数 WSAStartup 启动 WinSock DLL //--------------------------------------------------------------------------------------------------------------- WORD wVersionRequested; WSADATA wsaData; // 创建一个 WSADATA 结构体的变量, 这个变量是用来接收 Windows Sockets implementation. 的信息的 int err = 0; // 用来接收错误信息的 /*Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ wVersionRequested = MAKEWORD(1, 1); // Window Socket application 1.1 err = WSAStartup(wVersionRequested, &wsaData); // 创建成功返回 0 // 如果 启动 WinSock DLL 不成功 if (err != 0) { return; } // 如果版本信息与设置的不相同 if (HIBYTE(wsaData.wVersion) != 1 || LOBYTE(wsaData.wVersion) != 1) { return; } //--------------------------------------------------------------------------------------------------------------- // 使用函数 socket 创建套接字 //--------------------------------------------------------------------------------------------------------------- SOCKET socClient = socket(AF_INET,SOCK_STREAM,0); // 客户端不需要绑定 可以直接连接服务端 connect SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(6000); // 建立连接 connect(socClient,(SOCKADDR *)&addrSrv,sizeof(SOCKADDR)); char recvBuf[100]; recv(socClient,recvBuf,100,0); printf("%s\n",recvBuf); send(socClient,"This is Zhangsan",strlen("This is Zhangsan")+1,0); system("pause"); closesocket(socClient); WSACleanup(); // 终止对套接字库的使用 }