常用设计资源网站,wordpress more标签 无效,微信网页制作网站建设,亚马逊官方网站怎么做Socket编程中关于服务器端监听端口与新连接端口的深入剖析
在Socket编程领域#xff0c;存在一个容易让初学者感到困惑的问题。尽管很多人在网络上进行了相关探讨#xff0c;但不少解释要么不够清晰明了#xff0c;要么太过肤浅#xff0c;未能深入到问题的核心#xff0…Socket编程中关于服务器端监听端口与新连接端口的深入剖析
在Socket编程领域存在一个容易让初学者感到困惑的问题。尽管很多人在网络上进行了相关探讨但不少解释要么不够清晰明了要么太过肤浅未能深入到问题的核心这使得初学者在理解上存在诸多障碍。
其中一个关键问题是当Socket的服务端监听一个固定端口例如8888客户端前来连接此端口后服务器会生成一个新的Socket与对应的客户端进行通讯。那么这个新的Socket的发送和接收端口究竟是怎样的呢是随机分配的还是依然为8888在此明确地告诉读者答案是8888。即所有由该监听产生的回应客户端的新Socket其收发数据所使用的端口都是8888。后续将通过代码实现以及网络命令的展示来进一步验证这一点。
代码实现
服务端代码
#include iostream
#include winsock2.h
#include ws2tcpip.h
#pragma comment(lib, ws2_32.lib)#define DEFAULT_PORT 8888
#define DEFAULT_BUFLEN 1024int main() {// 1. 初始化 WinsockWSADATA wsaData;int iResult WSAStartup(MAKEWORD(2, 2), wsaData);if (iResult! 0) {std::cerr WSAStartup failed: iResult std::endl;return 1;}// 2. 创建套接字SOCKET ListenSocket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (ListenSocket INVALID_SOCKET) {std::cerr Socket creation failed: WSAGetLastError() std::endl;WSACleanup();return 1;}// 3. 绑定套接字到本地地址和端口sockaddr_in serverAddr;serverAddr.sin_family AF_INET;serverAddr.sin_addr.s_addr INADDR_ANY;serverAddr.sin_port htons(atoi(DEFAULT_PORT));iResult bind(ListenSocket, (sockaddr*)serverAddr, sizeof(serverAddr));if (iResult SOCKET_ERROR) {std::cerr Bind failed: WSAGetLastError() std::endl;closesocket(ListenSocket);WSACleanup();return 1;}// 4. 监听连接请求iResult listen(ListenSocket, SOMAXCONN);if (iResult SOCKET_ERROR) {std::cerr Listen failed: WSAGetLastError() std::endl;closesocket(ListenSocket);WSACleanup();return 1;}std::cout Server is listening on port DEFAULT_PORT ... std::endl;do {// 5. 接受客户端连接SOCKET ClientSocket accept(ListenSocket, NULL, NULL);if (ClientSocket INVALID_SOCKET) {std::cerr Accept failed: WSAGetLastError() std::endl;closesocket(ListenSocket);WSACleanup();return 1;}// 6. 接收和发送数据char recvbuf[DEFAULT_BUFLEN];int recvbuflen DEFAULT_BUFLEN;iResult recv(ClientSocket, recvbuf, recvbuflen, 0);if (iResult 0) {recvbuf[iResult] \0;std::cout Received from client: recvbuf std::endl;const char* sendbuf Hello from server!;iResult send(ClientSocket, sendbuf, strlen(sendbuf), 0);if (iResult SOCKET_ERROR) {std::cerr Send failed: WSAGetLastError() std::endl;}} else if (iResult 0) {std::cout Connection closing... std::endl;} else {std::cerr Recv failed: WSAGetLastError() std::endl;}} while (1);// 7. 关闭套接字//closesocket(ClientSocket);closesocket(ListenSocket);WSACleanup();return 0;
}这段服务端代码首先进行Winsock的初始化接着创建套接字、绑定到指定端口8888、开始监听连接请求。在接受客户端连接后能够接收客户端发送的数据并向客户端发送响应信息。
客户端代码
#include iostream
#include winsock2.h
#include ws2tcpip.h
#pragma comment(lib, ws2_32.lib)#define DEFAULT_PORT 8888
#define DEFAULT_BUFLEN 1024
#define SERVER_ADDR 127.0.0.1int main() {// 1. 初始化 WinsockWSADATA wsaData;int iResult WSAStartup(MAKEWORD(2, 2), wsaData);if (iResult! 0) {std::cerr WSAStartup failed: iResult std::endl;return 1;}// 2. 创建套接字SOCKET ConnectSocket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (ConnectSocket INVALID_SOCKET) {std::cerr Socket creation failed: WSAGetLastError() std::endl;WSACleanup();return 1;}// 3. 配置服务器地址结构体sockaddr_in serverAddr;serverAddr.sin_family AF_INET;serverAddr.sin_addr.s_addr inet_addr(SERVER_ADDR);serverAddr.sin_port htons(atoi(DEFAULT_PORT));// 4. 连接服务器iResult connect(ConnectSocket, (sockaddr*)serverAddr, sizeof(serverAddr));if (iResult SOCKET_ERROR) {std::cerr Connect failed: WSAGetLastError() std::endl;closesocket(ConnectSocket);WSACleanup();return 1;}std::cout Connected to server SERVER_ADDR : DEFAULT_PORT std::endl;// 5. 发送数据const char* sendbuf Hello from client!;iResult send(ConnectSocket, sendbuf, strlen(sendbuf), 0);if (iResult SOCKET_ERROR) {std::cerr Send failed: WSAGetLastError() std::endl;closesocket(ConnectSocket);WSACleanup();return 1;}// 6. 接收服务器响应char recvbuf[DEFAULT_BUFLEN];int recvbuflen DEFAULT_BUFLEN;iResult recv(ConnectSocket, recvbuf, recvbuflen, 0);if (iResult 0) {recvbuf[iResult] \0;std::cout Received from server: recvbuf std::endl;} else if (iResult 0) {std::cout Connection closing... std::endl;} else {std::cerr Recv failed: WSAGetLastError() std::endl;}getchar();// 7. 关闭套接字closesocket(ConnectSocket);WSACleanup();return 0;
}客户端代码同样先进行Winsock的初始化创建套接字后配置服务器地址并尝试连接到服务器地址为127.0.0.1端口8888。连接成功后发送数据给服务器并接收服务器的响应。
网络命令验证
使用Windows下的VC对上述代码进行编译链接生成socket_server.exe和socket_client.exe程序。
首先运行socket_server.exe程序此时网络监听情况如下服务进程PID18076
C:\Users\hssnetstat -ano | findstr :8888
TCP 0.0.0.0:8888 0.0.0.0:0 LISTENING 18076可以看到服务端在8888端口处于监听状态进程ID为18076。
接着分别运行2个客户端socket_client.exe程序网络监听和连接情况如下
C:\Users\hssnetstat -ano | findstr :8888
TCP 0.0.0.0:8888 0.0.0.0:0 LISTENING 18076
TCP 127.0.0.1:8888 127.0.0.1:35582 ESTABLISHED 18076
TCP 127.0.0.1:8888 127.0.0.1:35634 ESTABLISHED 18076
TCP 127.0.0.1:35582 127.0.0.1:8888 ESTABLISHED 5896
TCP 127.0.0.1:35634 127.0.0.1:8888 ESTABLISHED 22044从上述结果可以清晰地看出服务器进程ID为18076有1个监听的8888端口和2个与客户端建立的TCP连接且这些连接的本地收发端口都是8888。而客户端有2个进程ID分别为8896和22044它们的端口是随机分配的分别是35582和35634。
通过以上的代码实现和网络命令验证足以证明服务器监听返回的新的Socket链接的收发数据端口都是监听端口8888。这对于深入理解Socket编程中的端口使用机制具有重要意义能够帮助初学者更加准确地把握网络编程中这一关键知识点从而在后续的编程实践中避免因端口概念不清而产生的错误和困惑提升编程的准确性和效率为进一步深入学习网络编程奠定坚实的基础。