yak*_*yak 4 c++ winsock send recv winsock2
我想编写一个客户端/服务器应用程序,客户端和服务器可以在其中交换消息。
Client site communication:
send
recv
send
recv
Server site communication:
recv
send
recv
send
Run Code Online (Sandbox Code Playgroud)
但是,我有一个问题,因为只有一条消息是发送/接收。之后,套接字关闭,不再发送进一步的消息。出了什么问题,如何解决这个问题?谢谢你。
服务器代码:
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_PORT "27501"
#define SIZE 1024
int SendAllToClient(SOCKET ClientSocket, char *buffer)
{
int iSendResult;
int total = 0, len = 1024;
int bytesleft = 1024;
while( total < len )
{
iSendResult = send( ClientSocket, buffer, 1024, NULL);
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
total += iSendResult;
bytesleft -= iSendResult;
}
printf("Bytes sent: %d\n", iSendResult);
return total<len?- 1: 1;
}
char *ReadFromClient(SOCKET ConnectSocket)
{
int iResult;
char *buffer = new char[1024];
memset(buffer, 0, 1024);
do
{
iResult = recv(ConnectSocket, buffer, 1024, 0);
if ( iResult > 0 )
printf("Bytes received: %d\n", iResult);
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
}
while( iResult > 0 );
return buffer;
}
int main(int argc , char *argv[])
{
WSADATA wsaData;
char *buffer;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int sessionID;
int iResult;
// Datagram d1,d2,d3;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0)
{
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;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 )
{
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET)
{
printf("socket failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR)
{
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR)
{
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
printf("Server is listening on localhost:%s ...\n", DEFAULT_PORT);
// Accept a client socket
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
ClientSocket = accept(ListenSocket, (SOCKADDR*)&addr, &addrlen);
if (ClientSocket == INVALID_SOCKET)
{
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
char *ip = inet_ntoa(addr.sin_addr);
int port = addr.sin_port;
printf("\nClient %s:%d connected to server\n", ip, port);
// No longer need server socket
closesocket(ListenSocket);
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR)
{
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
//read
buffer = ReadFromClient(ClientSocket);
printf("FROM CLIENT: %s\n", buffer);
//send
memset(buffer, 0, 1024);
memcpy(buffer, "Hi client, how are you?", strlen("Hi client, how are you?"));
SendAllToClient(ClientSocket, buffer);
//read
//send
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
客户端代码:
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_PORT "27501"
#define SIZE 1024
int SendAllToServer(SOCKET ServerSocket, char *buffer)
{
int iSendResult;
int total = 0, len = 1024;
int bytesleft = 1024;
while( total < len )
{
iSendResult = send( ServerSocket, buffer, 1024, NULL);
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ServerSocket);
WSACleanup();
return 1;
}
total += iSendResult;
bytesleft -= iSendResult;
}
printf("Bytes sent: %d\n", iSendResult);
return total<len?- 1: 1;
}
char *ReadFromServer(SOCKET ConnectSocket)
{
int iResult;
char *buffer = new char[1024];
memset(buffer, 0, 1024);
do {
iResult = recv(ConnectSocket, buffer, 1024, 0);
if ( iResult > 0 )
printf("Bytes received: %d\n", iResult);
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
} while( iResult > 0 );
return buffer;
}
int main(int argc , char *argv[])
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char* buffer;
int sessionID;
int iResult;
// Datagram d1,d2;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
//send
buffer = new char[1024];
memset(buffer, 0, 1024);
memcpy(buffer, "Hi server", strlen("Hi server"));
SendAllToServer(ConnectSocket, buffer);
//read
memset(buffer, 0, 1024);
buffer = ReadFromServer(ConnectSocket);
printf("FROM SERVER: %s\n", buffer);
//send
//read
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编辑
服务器
#include "data_types.h"
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <iostream>
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_PORT "27015"
#define SIZE 1024
int SendAllToClient(SOCKET ClientSocket)
{
char *buffer = new char[SIZE];
int iSendResult;
memset(buffer, 0, SIZE);
int total = 0, len = SIZE;
int bytesleft = SIZE;
while( total < len )
{
iSendResult = send( ClientSocket, buffer + total, bytesleft, NULL);
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
total += iSendResult;
bytesleft -= iSendResult;
}
printf("Bytes sent: %d\n", iSendResult);
delete buffer;
return total<len?- 1: 1;
}
char* ReadFromClient(SOCKET ClientSocket)
{
std::string data = "";
char *all = NULL;
char buffer[1];
int total = 0, len = SIZE;
int bytesleft = SIZE;
int iResult;
memset(buffer, 0, 1);
while(total < len)
{
if ((iResult = recv(ClientSocket, buffer, 1, 0)) == 0)
{
if (errno != 0)
{
// cleanup
closesocket(ClientSocket);
WSACleanup();
exit(1);
}
}
data = data + std::string(buffer);
total += iResult;
bytesleft -= iResult;
memset(buffer, 0, 1);
}
all = new char[data.length() + 1];
strcpy(all, data.c_str());
return all;
}
int main(int argc , char *argv[])
{
WSADATA wsaData;
char *buffer;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int sessionID;
int iResult;
// Datagram d1,d2,d3;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0)
{
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;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 )
{
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET)
{
printf("socket failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR)
{
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR)
{
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
printf("Server is listening on localhost:%s ...\n", DEFAULT_PORT);
// Accept a client socket
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
ClientSocket = accept(ListenSocket, (SOCKADDR*)&addr, &addrlen);
if (ClientSocket == INVALID_SOCKET)
{
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
char *ip = inet_ntoa(addr.sin_addr);
int port = addr.sin_port;
printf("\nClient %s:%d connected to server\n", ip, port);
// No longer need server socket
closesocket(ListenSocket);
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR)
{
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
//read
buffer = new char[1024];
memset(buffer, 0, 1024);
buffer = ReadFromClient(ClientSocket);
printf("FROM CLIENT: %s\n", buffer);
//send
memset(buffer, 0, 1024);
memcpy(buffer, "Hi client, how are you?", strlen("Hi client, how are you?"));
// Send an initial buffer
iResult = send( ClientSocket, buffer, (int)strlen(buffer), 0 );
if (iResult == SOCKET_ERROR) {
wprintf(L"send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
//read
//send
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
客户
#include "data_types.h"
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <iostream>
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_PORT "27015"
#define SIZE 1024
int SendAllToServer(SOCKET ClientSocket)
{
char *buffer = new char[SIZE];
memset(buffer, 0, SIZE);
int total = 0, len = SIZE;
int bytesleft = SIZE, iSendResult;
while( total < len )
{
iSendResult = send( ClientSocket, buffer + total, bytesleft, NULL);
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
total += iSendResult;
bytesleft -= iSendResult;
}
printf("Bytes sent: %d\n", iSendResult);
delete buffer;
return total<len?- 1: 1;
}
char *ReadFromServer(SOCKET ClientSocket)
{
std::string data = "";
char *all = NULL;
char buffer[1];
int total = 0, len = SIZE;
int bytesleft = SIZE;
int iResult;
memset(buffer, 0, 1);
while(total < len)
{
if ((iResult = recv(ClientSocket, buffer, 1, 0)) == 0)
{
if (errno != 0)
{
// cleanup
closesocket(ClientSocket);
WSACleanup();
exit(1);
}
}
data = data + std::string(buffer);
total += iResult;
bytesleft -= iResult;
memset(buffer, 0, 1);
}
all = new char[data.length() + 1];
strcpy(all, data.c_str());
return all;
}
int main(int argc , char *argv[])
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char* buffer;
int sessionID;
int iResult;
// Datagram d1,d2;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
//send
buffer = new char[1024];
memset(buffer, 0, 1024);
memcpy(buffer, "Hi server, how are you?", strlen("Hi server, how are you?"));
// Send an initial buffer
iResult = send( ConnectSocket, buffer, (int)strlen(buffer), 0 );
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
//read
memset(buffer, 0, 1024);
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, buffer, 1024, 0);
if ( iResult > 0 )
wprintf(L"Bytes received: %d\n", iResult);
else if ( iResult == 0 )
wprintf(L"Connection closed\n");
else
wprintf(L"recv failed with error: %d\n", WSAGetLastError());
} while( iResult > 0 );
printf("FROM SERVER: %s\n", buffer);
//send
//read
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
First issue:
iSendResult = send( ClientSocket, buffer, 1024, NULL);
Run Code Online (Sandbox Code Playgroud)
That 1024 should be bytesleft. If you've already read 512 bytes, you don't want to read more than another 512.
That buffer should be buffer + total. If you've already sent 512 bytes, you don't want to send the same 512 bytes again, you want to send the other 512 bytes.
Second issue:
Your ReadFromServer function is just completely broken and doesn't follow the right logic. It only returns on a fatal error and doesn't even try to read exactly 1,024 bytes. It just reads up to 1,024 bytes and then, no matter how many bytes it actually read, tries to read 1,024 bytes again -- and at the same address overwriting whatever part of the message it already read!
It should work just like the send function, first trying to receive 1,024 bytes and looping if it receives less than that until it has either received exactly 1,024 bytes or gotten a fatal error.
Third issue:
buffer = ReadFromServer(ConnectSocket);
printf("FROM SERVER: %s\n", buffer);
Run Code Online (Sandbox Code Playgroud)
不要这样做。假设服务器是恶意的,并向您发送了 1,024 字节不是合法的 C 样式字符串。将其传递给printfthrough%s可能会导致客户端崩溃或行为不端。始终将从网络接收到的数据视为不受信任且可能具有敌意。尽管您的代码无需修复即可运行,但有一天这样做会以某种可怕的方式咬住您,这不是一个好习惯。
完成后,您还应该delete[]使用缓冲区。但是你为什么要返回一个原始指针呢?您可以返回 a std::string、 astd::vector或许多其他更好的机制,以避免泄漏风险并使副本安全。