- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我从简单的服务器开始 tutorial在 msdn 网站上学习如何在客户端和服务器应用程序中使用套接字。
完成教程后,我开始将客户端和服务器代码调整为多线程程序,以制作 tchat 客户端和服务器。在我遇到 WSA 错误 10048 之前,一切都进行得很顺利。我尝试为每个套接字使用不同的端口,但它仍然没有解决错误。
这是我的服务器代码:
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <thread>
#include <vector>
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")
//Global values
//I put them as global values in order to get the server up and running.
//I will try to pass them as params later on
int iResult;
struct addrinfo *result = NULL;
struct addrinfo hints;
int numClients = 0;
SOCKET ClientSocket[5];
std::thread** sendReceiveThread = new std::thread*[5];
//Prototypes
int listen(SOCKET ListenSocket);
int accept(SOCKET ListenSocket);
int sendReceive();
int shutdownFunction(SOCKET ClientSocket);
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT1 "1016"
#define DEFAULT_PORT2 "1017"
#define DEFAULT_PORT3 "1018"
#define DEFAULT_PORT4 "1019"
#define DEFAULT_PORT5 "1020"
int main()
{
std::cout << 1 << std::endl;
WSADATA wsaData;
SOCKET ListenSocket = INVALID_SOCKET;
// Initialize Winsock
std::cout << 2 << std::endl;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
std::cout << 3 << std::endl;
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
std::thread ListenThread{ [ListenSocket](){listen(ListenSocket); } };
ListenThread.join();
return 0;
}
int listen(SOCKET ListenSocket)
{
int numPort = 1;
std::vector<std::thread*> thread_vec;
while (true)
{
if (numPort == 1)
{
// Resolve the server address and port
std::cout << 4 << std::endl;
iResult = getaddrinfo(NULL, DEFAULT_PORT1, &hints, &result);
numPort++;
if (iResult != 0) {
std::cout << 5 << std::endl;
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
break;
}
}
else if (numPort == 2)
{
// Resolve the server address and port
std::cout << 4 << std::endl;
iResult = getaddrinfo(NULL, DEFAULT_PORT2, &hints, &result);
numPort++;
if (iResult != 0) {
std::cout << 5 << std::endl;
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
break;
}
}
else if (numPort == 3)
{
// Resolve the server address and port
std::cout << 4 << std::endl;
iResult = getaddrinfo(NULL, DEFAULT_PORT3, &hints, &result);
numPort++;
if (iResult != 0) {
std::cout << 5 << std::endl;
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
break;
}
}
else if (numPort == 4)
{
// Resolve the server address and port
std::cout << 4 << std::endl;
iResult = getaddrinfo(NULL, DEFAULT_PORT4, &hints, &result);
numPort++;
if (iResult != 0) {
std::cout << 5 << std::endl;
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
break;
}
}
else if (numPort == 5)
{
// Resolve the server address and port
std::cout << 4 << std::endl;
iResult = getaddrinfo(NULL, DEFAULT_PORT5, &hints, &result);
numPort++;
if (iResult != 0) {
std::cout << 5 << std::endl;
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
break;
}
}
// Create a SOCKET for connecting to server
std::cout << 6 << std::endl;
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
std::cout << 7 << std::endl;
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
break;
}
// Setup the TCP listening socket
std::cout << 8 << std::endl;
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
std::cout << 9 << std::endl;
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
break;
}
freeaddrinfo(result);
std::cout << 10 << std::endl;
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
std::cout << 11 << std::endl;
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
break;
}
static std::thread AcceptThread{ [ListenSocket](){accept(ListenSocket); } };
thread_vec.push_back(&AcceptThread);
}
for (auto it : thread_vec) it->join();
return 0;
}
int accept(SOCKET ListenSocket)
{
numClients++;
const int currentNumClients = numClients;
for (int i = 0; i <= 5; i++)
{
ClientSocket[i] = INVALID_SOCKET;
}
// Accept a client socket
std::cout << 12 << std::endl;
std::cout << 13 << std::endl;
ClientSocket[currentNumClients] = accept(ListenSocket, NULL, NULL);
if (ClientSocket[currentNumClients] == INVALID_SOCKET)
{
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
sendReceiveThread[currentNumClients] = new std::thread([](){sendReceive(); });
(*sendReceiveThread[currentNumClients]).join();
delete sendReceiveThread[currentNumClients];
return 0;
}
int sendReceive()
{
int currentNumClients = numClients;
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
// Receive until the peer shuts down the connection
while(true)
{
std::cout << 14 << std::endl;
iResult = recv(ClientSocket[currentNumClients], recvbuf, recvbuflen, 0);
std::cout << iResult << std::endl;
if (iResult > 0) {
std::cout << 15 << std::endl;
printf("Bytes received: %d\n", iResult);
// Echo the buffer back to the clients
std::cout << 16 << std::endl;
for (int i = 1; i <= numClients; i++)
{
iSendResult = send(ClientSocket[currentNumClients], recvbuf, iResult, 0);
if (iSendResult == SOCKET_ERROR) {
std::cout << 17 << std::endl;
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket[currentNumClients]);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
}
}
else if (iResult == 0) {
std::cout << 18 << std::endl;
printf("Connection closing...\n");
break;
}
else {
std::cout << 19 << std::endl;
printf("recv failed with error: %d\n", WSAGetLastError());
std::cout << "On client #" << currentNumClients << std::endl;
break;
}
}
iResult = shutdownFunction(ClientSocket[currentNumClients]);
std::cout << 22 << std::endl;
// cleanup
closesocket(ClientSocket[currentNumClients]);
WSACleanup();
return 0;
}
int shutdownFunction(SOCKET ClientSocket)
{
std::cout << 20 << std::endl;
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
std::cout << 21 << std::endl;
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
return 0;
}
您可能会注意到不同的 cout,这些只是了解程序行为的 cout。
最佳答案
WSA 10048 是“地址正在使用”错误 (https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx)。
我没有 Windows,所以我无法运行您的代码,但是当服务器将服务器端口保留几分钟才能重新使用时,通常会发生此错误。
提供套接字选项以允许更快的重用,setsockopt (SO_REUSEADDR)。
在您的情况下,您将在创建并检查 ListenSocket
后立即添加以下行:
int optval = 1;
iResult = ::setsockopt(ListenSocket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
if (iResult == SOCKET_ERROR) {
std::cout << 9 << std::endl;
printf("setsockopt failed with error: %d\n", WSAGetLastError());
}
TCP 堆栈有充分的理由不在旧端口号发布后立即重新发布它们,但对于服务器端口来说,这是不需要的行为。只是,堆栈不知道服务器端口和非服务器端口之间的区别,所以我们必须使用 setsockopt。
关于c++ - 绑定(bind)服务器套接字时出现 WSA 错误 10048,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31912162/
我在 win32 c++ 应用程序中使用 winsock2。我会用 MessageBox 显示我可以通过调用 WSAGetLastError() 检索的网络错误。我怎样才能做到这一点?我看到了 For
我一直在尝试用 C++ 编写一个简单的聊天程序,但遇到了一个套接字问题。以下代码正在返回 上次错误代码为(1):0 最后一个错误代码是(2): 0 上次错误代码为 (3):10049 最后的错误代码是
RAII 在调用 exit 时不执行析构函数。所以 WSACleanup不运行。有什么问题?我发现 libnet 使用 WSAStartup没有任何 WSACleanup,为什么? WSAStartu
我目前正在尝试实现一个类来创建和使用 TCP 连接。 (我是 c++ 的新手,所以我可能忘记了一些明显的东西,尽管我一直在认真检查我的代码) 请注意,稍后我将实现第二个类来处理新连接,因此代码的某些部
我从简单的服务器 tutorial 开始在 msdn 网站上,了解如何在客户端和服务器应用程序中使用套接字。 完成教程后,我开始将客户端和服务器代码改编为多线程程序,以便制作 tchat 客户端和服务
我正在学习 C++,我想尝试实现一个非常简单的 HTTP 服务器,它只会输出一条文本消息。我使用 Microsoft Visual Studio 2005。 我得到:第 20 行:警告“wsa”未引用
我从简单的服务器开始 tutorial在 msdn 网站上学习如何在客户端和服务器应用程序中使用套接字。 完成教程后,我开始将客户端和服务器代码调整为多线程程序,以制作 tchat 客户端和服务器。在
客户: //is called when the client tries to log in procedure TLogin_Form.btnLoginClick(Sender: TObj
我有一个需要使用异步 Web 服务的应用程序,该服务需要 header 中的 wsa:MesssageId、wsa:ReplyTo wsa:address 和 ws:To。虽然 wsa:Message
我是 WSO2 ESB 的新手。我正在为基于 SOAP 的服务做服务代理。其中我的端点服务有多种方法。谁能建议我如何在我的流程文件中声明一个特定的操作(方法)。因为我正在获取未找到操作的端点引用。 下
我是一名优秀的程序员,十分优秀!