非常感谢这篇文章的博主的逐个函数讲解,让我有了更清晰的认识!
基础函数介绍:https://www.jianshu.com/p/3b233facd6bb
C++ socket编程:
IDE:VS2019;
我建立两个工程,一个作为服务器端,一个作为客户端,debug之后,运行连接。
先搞清上述基本函数之后再编写十分简单。
源码文件在最后
服务器端:
// server.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
```cpp
#include<stdio.h>
#include<string.h>
#include<WinSock2.h>
#include <iostream>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#pragma comment(lib,"ws2_32.lib")
int main()
{
/*加载winsock文件*/
//WSADATA结构被用来储存调用AfxSocketInit全局函数返回的Windows Sockets初始化信息
//初始化WSA
WORD sockVersion = MAKEWORD(2, 0); //使用WINSOCK2版本
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0)//第一个参数是WINSOCK 版本号,第二个参数是指向WSADATA的指针.
{
return 0; //该函数返回一个INT型值,通过检查这个值来确定初始化是否成功
}
std::cout << "This is server !" << std::endl;
int slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//0:自动选择类型对应的默认协议
if (slisten == -1)
{
std::cout << "socket error !";
return 0;
}
//绑定ip地址和端口
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.S_un.S_addr = INADDR_ANY;//参见in_addr结构,csdn上找一找就能找到
//INADDR_ANY:转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的所有IP
//当PC有多块网卡时,可以使用这个,只需管理一个套接字,便可以监听所有网卡端口号数据
if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
std::cout<<"bind error !"<<std::endl;
}
//开始监听
if (listen(slisten, 5) == SOCKET_ERROR)//slisten:要监听的socket描述字,5:相应的socket可以排队的最大连接数
{
std::cout << "listen error !";
return 0;
}
SOCKET sClient;
sockaddr_in clientAddr;
int clientAddrlen = sizeof(clientAddr);
while (true)
{
std::cout << "...listening" << std::endl;
sClient = accept(slisten, (SOCKADDR*)&clientAddr, &clientAddrlen);
if (sClient == INVALID_SOCKET)
{
std::cout << "accept error !";
continue;
}
inet_ntoa(clientAddr.sin_addr);
std::cout << "...connect" <<ntohs(clientAddr.sin_port)<< std::endl;
//接收数据
char buf[255];
while (true)
{
memset(buf, 0, 255);//清空脏数据
int len = recv(sClient, buf, 255, 0);
buf[len] = '\0';
if (strcmp(buf, "end" )==0)//以end为结束标志,收到end则断开连接
{
std::cout << "...disconnect" << ntohs(clientAddr.sin_port) << std::endl;
break;
}
std::cout << buf << std::endl;
//发送数据
send(sClient, buf, strlen(buf), 0);
//这里是发送回接收到的数据,可以根据要求自己修改发送回的数据
/*char Data[255];*/
/*std::cin >> Data;
send(sClient, Data, strlen(Data), 0);*/
}
closesocket(sClient);
}
closesocket(slisten);
WSACleanup();
//关闭套接字,关闭加载的套接字库
return 0;
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件
客户端:
```cpp
#include<WinSock2.h>
#include<stdio.h>
#include<iostream>
#include<cstring>
#include<string>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main()
{
//初始化
WORD sockVersion = MAKEWORD(2, 2);
WSADATA data;
if (WSAStartup(sockVersion, &data) != 0)
{
return 0;
}
//建立套接字结构
cout << "This is Client !" << endl;
SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sclient == -1)
{
cout << "socket error !" << endl;
return 0;
}
//连接connect
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8888);
serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (connect(sclient,(struct sockaddr*)&serAddr,sizeof(serAddr))<0)
{
cout << "Connect error !" << endl;
return 0;
}
std::cout << "...connect" << std::endl;
char buf[255];
char Data[255];
while (true)
{
cin >> buf;
send(sclient, buf, strlen(buf), 0);
//send()用来将数据由指定的socket传给对方主机
//int send(int s, const void * msg, int len, unsigned int flags)flags一般设0
if (strcmp(buf, "end") == 0) {
cout << "...disconnect" << endl;
break;
}
memset(Data, 0, sizeof(Data));
recv(sclient, Data, sizeof(Data), 0);
cout << Data << endl;
}
}
运行效果:
源码:https://pan.baidu.com/s/14i6FCZTKC4sjgEi9kWu5dg
提取码:txns