实验前知识准备:
微软的socket开发文档,包含api的用法及解释:
https://docs.microsoft.com/zh-cn/windows/win32/api/_winsock/
1.什么是socket:我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。(简单来说就是相互打电话,通讯建立时socket就相当于通话双方的电话线)
我们知道两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。能够唯一标示网络中的进程后,它们就可以利用socket进行通信了。
逻辑关系如下
2.socket通信流程:socket是"打开—读/写—关闭"模式的实现,以使用TCP协议通讯的socket为例,其交互流程大概是这样子的
3.服务器端编程的步骤:
1):加载套接字库,创建套接字(WSAStartup()/socket());
2):绑定套接字到一个IP地址和一个端口上(bind());
3):将套接字设置为监听模式等待连接请求(listen());
4):请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());
5):用返回的套接字和客户端进行通信(send()/recv());
6):返回,等待另一连接请求;
7):关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。
4.代码示例(简要的用代码实现连接建立的过程
#include #include #include #include #pragma comment(lib, "ws2_32.lib")int main(int argc, char *argv[]){ //初始化socket WORD sockVersion = MAKEWORD(2, 2); WSAData wasData; if (0 != WSAStartup(sockVersion, &wasData)) { return 0; } //创建套接字 SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //如果为空 if (slisten == INVALID_SOCKET) { printf("套接字创建失败"); return 0; } //服务器绑定需要的ip和端口 sockaddr_in sin; //addr地址 sin.sin_family = AF_INET; //ipv4 sin.sin_port = htons(80); //设置端口 sin.sin_addr.S_un.S_addr = INADDR_ANY; //任意地址都可以访问 //绑定 if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) { printf("绑定地址失败"); } //开始监听 if (listen(slisten, 5) == SOCKET_ERROR) //可以监听的数量 { printf("监听失败"); } //接听后 通过Tcp传数据 SOCKET sClient; //接收套接字 sockaddr_in remoteAddr; //对方地址 int nAddrlen = sizeof(remoteAddr); char revData[1024]; while (1) //服务器一直服务 { printf("等待连接...\n"); //存储通信的socket sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen); if (sClient == INVALID_SOCKET) { printf("连接失败"); continue; } char sendBuf[20] = { '\0' }; printf("收到一个连接:%s \r\n",inet_ntoa(remoteAddr.sin_addr)); //接下来需要同学们来处理请求的数据 } //防止控制台一闪而过 getchar();}
打开浏览器,输入本地ip,即127.0.0.1,看到控制台回显如下
至此,连接建立成功!根据需求来完善上述代码,比如返回页面或者服务器上的文件