一、socket通讯开发步骤
1、创建socket
1.1、指定服务端相关信息系
指定socket版本号 如: winsock_ver = MAKEWORD(2, 2);
addr_len = sizeof(SOCKADDR_IN);
//指定ip地址族
addr_svr.sin_family = AF_INET;
//转换网络编码,指定侦听本地端口
addr_svr.sin_port = ::htons(SERVER_PORT);
//设置接收任意地址的连接
addr_svr.sin_addr.S_un.S_addr = ADDR_ANY;
//设置某一指定内存内容为0;
memset(buf_ip, 0, IP_BUF_SIZE)将buf_ip全部指定为0, IP_BUF_SIZE:IP地址长度
1.2、启动socket
//WSAStartup,即WSA(Windows Sockets Asynchronous,Windows异步套接字)的启动命令。0表示成功
ret_val = ::WSAStartup(winsock_ver, &wsa_data);
if (ret_val != 0)
{
cerr << "WSA failed to start up!Error code: " << ::WSAGetLastError() << "\n";
system("pause");
exit(1);
}
cout << "WSA started up successfully...\n";
1.3、创建服务端socket
//创建socket socket如果调用成功就返回新创建的套接字的描述符
sock_svr = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock_svr == INVALID_SOCKET)
{
cerr << "Failed to create server socket!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit(1);
}
cout << "Server socket created successfully...\n";
2、绑定
//bind 绑定要通信的程序,成为服务器,如果函数执行成功,返回值为0,否则为SOCKET_ERROR。
//sock_svr就是第二步成功买回的,不,是申请到的接口
//(SOCKADDR*)&addr_svr 是指进程具体地址,就像具体电话号码一样,他的类型是一个结构体
//addr_len就是位置的长度
ret_val = ::bind(sock_svr, (SOCKADDR*)&addr_svr, addr_len);
if (ret_val != 0)
{
cerr << "Failed to bind server socket!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit(1);
}
cout << "Server socket bound successfully...\n";
3、监听端口
ret_val = ::listen(sock_svr, SOMAXCONN);
if (ret_val == SOCKET_ERROR)
{
cerr << "Server socket failed to listen!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit(1);
}
cout << "Server socket started to listen...\n";
//
cout << "Server started successfully..." << endl;
4、等待客户端,
while (true)
{
//接受客户端的信息
sock_clt = ::accept(sock_svr, (SOCKADDR*)&addr_clt, &addr_len);
cout << "ssss " << sock_clt << endl;
if (sock_clt == INVALID_SOCKET)
{
cout << "ssss " << sock_clt <
5、接收客户端发送的信息、发送信息给客户端
char buf_msg[MSG_BUF_SIZE]; // 接收信息
int ret_val = 0; //返回读入字节数
int snd_result = 0; //返回发送信息字节数
do
{
memset(buf_msg, 0, MSG_BUF_SIZE);
//接收数据 若无错误,返回读入字节数
ret_val = ::recv(sock_clt, buf_msg, MSG_BUF_SIZE, 0);
if (ret_val > 0)
{
//如果接送的信息为“exit”,则关闭连接
if (strcmp(buf_msg, "exit") == 0)
{
cout << "Client requests to close the connection..." << endl;
break;
}
//打印接收信息
cout << "Message received: " << buf_msg << endl;
//发送消息给客户端
char send_to_client[SEND_BUF_SIZE]; //发送给客户端的信息
cout << "enter the message that you want to send client: " << flush;
cin.getline(send_to_client, SEND_BUF_SIZE);//控制台输入需要发送信息
cout << "enter the message " << send_to_client << endl;
snd_result = ::send(sock_clt, send_to_client, static_cast(strlen(send_to_client)), 0);
//snd_result = ::send(sock_clt, buf_msg, MSG_BUF_SIZE, 0);
//如果发送失败,即snd_result=-1
if (snd_result == SOCKET_ERROR)
{
cerr << "Failed to send message to client!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return 1;
}
}//接受信息失败ret_val==0
else if (ret_val == 0)
{
cout << "connection closed..." << endl;
}
else
{
cerr << "Failed to receive message from client!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return 1;
}
} while (ret_val > 0);
//
ret_val = ::shutdown(sock_clt, SD_SEND);
if (ret_val == SOCKET_ERROR)
{
cerr << "Failed to shutdown the client socket!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return 1;
}
6、创建客户端socket
6.1、同样先创建socket
WSADATA wsa_data; //WSADATA变量,包含windows socket执行的信息
int i_result = 0; //接收返回值
SOCKET sock_client = INVALID_SOCKET;
addrinfo *result = nullptr, hints;
//初始化winsock动态库(ws2_32.dll),MAKEWORD(2, 2)用于请求使用winsock2.2版本
i_result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (i_result != 0) {
cerr << "WSAStartup() function failed: " << i_result << "\n";
system("pause");
return 1;
}
SecureZeroMemory(&hints, sizeof(hints));//其作用是用0来填充一块内存区域
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
//getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,
//返回的是一个sockaddr结构的链表而不是一个地址清单。
//这些sockaddr结构随后可由套接口函数直接使用
i_result = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
if (i_result != 0) {
cerr << "getaddrinfo() function failed with error: " << WSAGetLastError() << "\n";
WSACleanup();
system("pause");
return 1;
}
//创建套接字
sock_client = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (sock_client == INVALID_SOCKET) {
cerr << "socket() function failed with error: " << WSAGetLastError() << "\n";
WSACleanup();
system("pause");
return 1;
}
6.2、连接服务器
//连接服务器
i_result = connect(sock_client, result->ai_addr, result->ai_addrlen);
if (i_result == SOCKET_ERROR) {
cerr << "connect() function failed with error: " << WSAGetLastError() << "\n";
WSACleanup();
system("pause");
return 1;
}
cout << "connect server successfully..." << endl;
//释放由getaddrinfo返回的存储空间,包括addrinfo结构、ai_addr结构和ai_canonname字符串
freeaddrinfo(result);
6.3、发送信息给服务端
//发送信息给服务端
char send_buf[SEND_BUF_SIZE];
int recv_result = 0; //接收服务器返回的数据的返回值
//SecureZeroMemory(send_buf, SEND_BUF_SIZE);
do {
cout << "enter the message that you want to send: " << flush;
cin.getline(send_buf, SEND_BUF_SIZE);
i_result = send(sock_client, send_buf, static_cast(strlen(send_buf)), 0);
if (i_result == SOCKET_ERROR) {
cerr << "send() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return 1;
}
cout << "Bytes sent: " << i_result << endl;
//接收服务器返回的数据
char rec_from_server[SEND_BUF_SIZE];
recv_result = recv(sock_client, rec_from_server, SEND_BUF_SIZE, 0);
//recv_result = recv(sock_client, send_buf, SEND_BUF_SIZE, 0);
if (recv_result > 0) {
cout << "feedback from server: " << rec_from_server << endl;
//cout << "feedback from server: " << send_buf << endl;
}
else if (recv_result == 0) {
cout << "connection closed..." << endl;
}
else {
cerr << "recv() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return 1;
}
} while (recv_result > 0);
7、关闭socket
i_result = shutdown(sock_client, SD_SEND);
if (i_result == SOCKET_ERROR) {
cerr << "shutdown() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return 1;
}
closesocket(sock_client);
WSACleanup();
cout << "socket closed..." << endl;
服务端代码:
1、socketserver.h
#pragma once
#ifndef SOCKETSERVER_H
#define SOCKETSERVER_H
#include
#include
#pragma comment (lib, "ws2_32.lib")
#define IP_BUF_SIZE 129
class Server
{
public:
Server();
~Server();
Server(const Server &) = delete;
Server & operator=(const Server &) = delete;
void WaitForClient();
private:
WORD winsock_ver; //socket版本
WSADATA wsa_data; //存储被WSAStartup函数调用后返回的Windows Sockets数据
SOCKET sock_svr; //服务端socket
SOCKET sock_clt; //客户端socket
HANDLE h_thread; //创建的线程
SOCKADDR_IN addr_svr; //存放了服务端地址族、端口、ip地址,用来处理通信地址
SOCKADDR_IN addr_clt; //存放了客户端地址族、端口、ip地址,用来处理通信地址
int ret_val;
int addr_len;
char buf_ip[IP_BUF_SIZE];
};
#endif
2、socketserver.cpp
#include "pch.h"
#include "socketserver.h"
#include
#include
using namespace std;
#define SERVER_PORT 5000 //端口
#define MSG_BUF_SIZE 1024 //接送信息最大长度
const int SEND_BUF_SIZE = 1024; //发送信息最大长度
Server::Server()
{
cout << "Initializing server...\n";
//
winsock_ver = MAKEWORD(2, 2); //指定socket版本2.2
addr_len = sizeof(SOCKADDR_IN);
addr_svr.sin_family = AF_INET; //ip地址族
addr_svr.sin_port = ::htons(SERVER_PORT); //转换网络编码,侦听本地5000端口
addr_svr.sin_addr.S_un.S_addr = ADDR_ANY; //接收任意地址的连接
//memset某一块内存中的内容全部设置为指定的值,
//这个函数通常为新申请的内存做初始化工作。
memset(buf_ip, 0, IP_BUF_SIZE);//将buf_ip全部指定为0
//WSAStartup,即WSA(Windows Sockets Asynchronous,Windows异步套接字)的启动命令。0表示成功
ret_val = ::WSAStartup(winsock_ver, &wsa_data);
if (ret_val != 0)
{
cerr << "WSA failed to start up!Error code: " << ::WSAGetLastError() << "\n";
system("pause");
exit(1);
}
cout << "WSA started up successfully...\n";
//创建socket socket如果调用成功就返回新创建的套接字的描述符
sock_svr = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock_svr == INVALID_SOCKET)
{
cerr << "Failed to create server socket!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit(1);
}
cout << "Server socket created successfully...\n";
//bind 绑定要通信的程序,成为服务器,如果函数执行成功,返回值为0,否则为SOCKET_ERROR。
//sock_svr就是第二步成功买回的,不,是申请到的接口
//(SOCKADDR*)&addr_svr 是指进程具体地址,就像具体电话号码一样,他的类型是一个结构体
//addr_len就是位置的长度
ret_val = ::bind(sock_svr, (SOCKADDR*)&addr_svr, addr_len);
if (ret_val != 0)
{
cerr << "Failed to bind server socket!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit(1);
}
cout << "Server socket bound successfully...\n";
//监听端口
ret_val = ::listen(sock_svr, SOMAXCONN);
if (ret_val == SOCKET_ERROR)
{
cerr << "Server socket failed to listen!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit(1);
}
cout << "Server socket started to listen...\n";
//
cout << "Server started successfully..." << endl;
cout << "ret_val..." << ret_val << endl;
}
Server::~Server()
{
::closesocket(sock_svr);
::closesocket(sock_clt);
::WSACleanup();
cout << "Socket closed..." << endl;
}
DWORD WINAPI CreateClientThread(LPVOID lpParameter);
//等待客户端
void Server::WaitForClient()
{
while (true)
{
//接受客户端的信息
sock_clt = ::accept(sock_svr, (SOCKADDR*)&addr_clt, &addr_len);
cout << "ssss " << sock_clt << endl;
if (sock_clt == INVALID_SOCKET)
{
cout << "ssss " << sock_clt < 0)
{
//如果接送的信息为“exit”,则关闭连接
if (strcmp(buf_msg, "exit") == 0)
{
cout << "Client requests to close the connection..." << endl;
break;
}
//打印接收信息
cout << "Message received: " << buf_msg << endl;
//发送消息给客户端
char send_to_client[SEND_BUF_SIZE]; //发送给客户端的信息
cout << "enter the message that you want to send client: " << flush;
cin.getline(send_to_client, SEND_BUF_SIZE);//控制台输入需要发送信息
cout << "enter the message " << send_to_client << endl;
snd_result = ::send(sock_clt, send_to_client, static_cast(strlen(send_to_client)), 0);
//snd_result = ::send(sock_clt, buf_msg, MSG_BUF_SIZE, 0);
//如果发送失败,即snd_result=-1
if (snd_result == SOCKET_ERROR)
{
cerr << "Failed to send message to client!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return 1;
}
}//接受信息失败ret_val==0
else if (ret_val == 0)
{
cout << "connection closed..." << endl;
}
else
{
cerr << "Failed to receive message from client!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return 1;
}
} while (ret_val > 0);
//
ret_val = ::shutdown(sock_clt, SD_SEND);
if (ret_val == SOCKET_ERROR)
{
cerr << "Failed to shutdown the client socket!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return 1;
}
return 0;
}
3、启动服务端代码
#include "pch.h"
#include "socketserver.h"
int main()
{
Server svr;
svr.WaitForClient();
system("pause");
return 0;
}
4、客户端代码
#include
#include
#include
#pragma comment(lib, "ws2_32.lib")
using std::cin;
using std::cerr;
using std::cout;
using std::endl;
using std::flush;
const char DEFAULT_PORT[] = "5000";
const int SEND_BUF_SIZE = 1024;
//客户端
int main() {
WSADATA wsa_data; //WSADATA变量,包含windows socket执行的信息
int i_result = 0; //接收返回值
SOCKET sock_client = INVALID_SOCKET;
addrinfo *result = nullptr, hints;
//初始化winsock动态库(ws2_32.dll),MAKEWORD(2, 2)用于请求使用winsock2.2版本
i_result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (i_result != 0) {
cerr << "WSAStartup() function failed: " << i_result << "\n";
system("pause");
return 1;
}
SecureZeroMemory(&hints, sizeof(hints));//其作用是用0来填充一块内存区域
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
//getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,
//返回的是一个sockaddr结构的链表而不是一个地址清单。
//这些sockaddr结构随后可由套接口函数直接使用
i_result = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
if (i_result != 0) {
cerr << "getaddrinfo() function failed with error: " << WSAGetLastError() << "\n";
WSACleanup();
system("pause");
return 1;
}
//创建套接字
sock_client = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (sock_client == INVALID_SOCKET) {
cerr << "socket() function failed with error: " << WSAGetLastError() << "\n";
WSACleanup();
system("pause");
return 1;
}
//连接服务器
i_result = connect(sock_client, result->ai_addr, result->ai_addrlen);
if (i_result == SOCKET_ERROR) {
cerr << "connect() function failed with error: " << WSAGetLastError() << "\n";
WSACleanup();
system("pause");
return 1;
}
cout << "connect server successfully..." << endl;
//释放由getaddrinfo返回的存储空间,包括addrinfo结构、ai_addr结构和ai_canonname字符串
freeaddrinfo(result);
//发送信息给服务端
char send_buf[SEND_BUF_SIZE];
int recv_result = 0; //接收服务器返回的数据的返回值
//SecureZeroMemory(send_buf, SEND_BUF_SIZE);
do {
cout << "enter the message that you want to send: " << flush;
cin.getline(send_buf, SEND_BUF_SIZE);
i_result = send(sock_client, send_buf, static_cast(strlen(send_buf)), 0);
if (i_result == SOCKET_ERROR) {
cerr << "send() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return 1;
}
cout << "Bytes sent: " << i_result << endl;
//接收服务器返回的数据
char rec_from_server[SEND_BUF_SIZE];
recv_result = recv(sock_client, rec_from_server, SEND_BUF_SIZE, 0);
//recv_result = recv(sock_client, send_buf, SEND_BUF_SIZE, 0);
if (recv_result > 0) {
cout << "feedback from server: " << rec_from_server << endl;
//cout << "feedback from server: " << send_buf << endl;
}
else if (recv_result == 0) {
cout << "connection closed..." << endl;
}
else {
cerr << "recv() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return 1;
}
} while (recv_result > 0);
//
i_result = shutdown(sock_client, SD_SEND);
if (i_result == SOCKET_ERROR) {
cerr << "shutdown() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return 1;
}
closesocket(sock_client);
WSACleanup();
cout << "socket closed..." << endl;
system("pause");
return 0;
}