计算机网络基本知识
Windows Sockets的实现
套接字类型
- 流式套接字/SOCK_STREAM: TCP
- 数据报文套接字/SOCK_DGRAM: UDP
- 原始套接字/SOCK_RAW
基于TCP(面向连接)的socket编程
服务器端
- 创建套接字: socket
- 套接字绑定到一个本地地址和端口上(bind)
- 接字设为监听模式,准备接收客户请求(listen)
- 等待客户请求到来(accept); 当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字。
- 用返回的套接字和客户端进行通信(send/recv)。
- 返回,等待另一客户请求。
- 闭套接字。
客户端
- 创建套接字
- 向服务器发出连接请求(connect)。
- 服务器端进行通信(send/recv)。
- 关闭套接字。
服务器端,当调用 accept 函数时,程序就会等待,等待客户端调用 connect函数发出连接请求,然后服务器端接受该请求,于是双方就建立了连接。之后,服务器端和客户端就可以利用 send和 recv函数进行通信了
基于UDP(面向无连接)的socket编程
相关函数
-
int WSAStartup(WORD wVersionRequired,[out] LPWSADATA lpWSAData);
-
SOCKET WSAAPI socket( [in] int af, [in] int type, [in] int protocol ); -
int WSAAPI bind( [in] SOCKET s, [in] const sockaddr *name, [in] int namelen ); inet_addr和inet_ntoa: 以将 IP地址指定为
INADDR_ANY,允许套接字向任何分配给本地机器的 IP地址发送或接收数据 ```cpp unsigned long WSAAPI inet_addr( const char *cp );
char *WSAAPI inet_ntoa( in_addr in );
- [inet_pton ](https://docs.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-inet_pton)和 [inet_ntop](https://docs.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-inet_ntop): 两个函数是为了适应 IPv6 而出现的,用于将 Internet 网络地址在"标准文本表示形式"和"数字二进制形式"之间进行转换,对于IPv4 地址和 IPv6 地址都适用,函数中p和 n 分别代表表达(presentation)和数值(numeric)
```cpp
PCSTR WSAAPI inet_ntop(
[in] INT Family,
[in] const VOID *pAddr,
[out] PSTR pStringBuf,
[in] size_t StringBufSize
);
char *WSAAPI inet_ntoa(
in_addr in
);
-
int WSAAPI listen( [in] SOCKET s, [in] int backlog ); -
SOCKET WSAAPI accept( [in] SOCKET s, [out] sockaddr *addr, [in, out] int *addrlen ); -
int WSAAPI send( [in] SOCKET s, [in] const char *buf, [in] int len, [in] int flags ); -
int WSAAPI recv( [in] SOCKET s, [out] char *buf, [in] int len, [in] int flags ); -
int WSAAPI connect( [in] SOCKET s, [in] const sockaddr *name, [in] int namelen ); -
int WSAAPI recvfrom( [in] SOCKET s, [out] char *buf, [in] int len, [in] int flags, [out] sockaddr *from, [in, out, optional] int *fromlen ); -
int WSAAPI sendto( [in] SOCKET s, [in] const char *buf, [in] int len, [in] int flags, [in] const sockaddr *to, [in] int tolen ); htons和htonl ```cpp u_short WSAAPI htons( [in] u_short hostshort );
u_long WSAAPI htonl( [in] u_long hostlong );
<a name="NtRDz"></a>
# 基于TCP的网络应用程序的编写
<a name="YKScE"></a>
## 服务器端
```cpp
#include <Winsock2.h>
#include <iostream>
#include <Ws2tcpip.h>
#pragma comment(lib,"Ws2_32.lib")
int main() {
//加载套接字库
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
return -1;
}
if (LOBYTE(wsaData.wVersion) != 1 ||
HIBYTE(wsaData.wVersion) != 1) {
WSACleanup();
return -1;
}
//创建用于监听的套接字
SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
//绑定套接字
bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
//将套接字设为监听模式,准备接收客户请求
listen(sockSrv, 5);
SOCKADDR_IN addrClient;
int len = sizeof(SOCKADDR);
while (1)
{
//等待客户请求到来
SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrClient, &len);
char sendBuf[100];
char str[INET_ADDRSTRLEN];
sprintf_s(sendBuf, 100, "Welcome %s to http://www.phei.com.cn",
inet_ntop(AF_INET, &addrClient.sin_addr, str, sizeof(str)));
//发送数据
send(sockConn, sendBuf, strlen(sendBuf) + 1, 0);
char recvBuf[100];
//接收数据
recv(sockConn, recvBuf, 100, 0);
//打印接收的数据
printf("%s\n", recvBuf);
//关闭套接字
closesocket(sockConn);
}
return 0;
}
客户端
#include <iostream>
#include <Winsock2.h>
#include <Ws2tcpip.h>
#pragma comment(lib,"Ws2_32.lib")
int main()
{
//加载套接字库
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
return -1;
}
if (LOBYTE(wsaData.wVersion) != 1 ||
HIBYTE(wsaData.wVersion) != 1) {
WSACleanup();
return -1;
}
//创建套接字
SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv;
inet_pton(AF_INET, "127.0.0.1", &addrSrv.sin_addr);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
//向服务器发出连接请求
connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
//接收数据
char recvBuf[100];
recv(sockClient, recvBuf, 100, 0);
printf("%s\n", recvBuf);
//发送数据
send(sockClient, "This is 李四", strlen("This is 李四") + 1, 0);
//关闭套接字
closesocket(sockClient);
WSACleanup();
system("PAUSE ");
return 0;
}
