C++:实现socket通信(TCPIP)实例

    xiaoxiao2022-07-04  218

    刚接触socket通信,网上一篇简单通俗,很有概括性的文章,值得入门一看。

    原文地址见篇尾

    以下是原文内容:

    首先声明,博主之前从来没有写过通信方面的东西,这次之所以写这个是因为项目需要,因此本文主要介绍一个使用C++语言及Socket来实现TCP/IP通信的实例,希望可以帮助入门者。

    一、什么是TCP/IP?

            TCP提供基于IP环境下的数据可靠性传输,事先需要进行三次握手来确保数据传输的可靠性。详细的博主不再赘述,感兴趣的朋友可以去search一下。

    二、什么是socket?    

            socket顾名思义就是套接字的意思,用于描述地址和端口,是一个通信链的句柄。应用程序通过socket向网络发出请求或者回应。

            socket编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW),前两者较常用。基于TCP的socket编程是流式套接字。

    三、client/server即C/S模式:

           TCP/IP通信中,主要是进行C/S交互。废话不多说,下面看看具体交互内容:

           服务端:建立socket,申明自身的port和IP,并绑定到socket,使用listen监听,然后不断用accept去查看是否有连接。如果有,捕获socket,并通过recv获取消息的内容,通信完成后调用closeSocket关闭这个对应accept到的socket。如果不需要等待任何客户端连接,那么用closeSocket直接关闭自身的socket。

            客户端:建立socket,通过端口号和地址确定目标服务器,使用Connect连接到服务器,send发送消息,等待处理,通信完成后调用closeSocket关闭socket。

    四、编程步骤

    1、server端  

    #include<winsock.h> #pragma comment(lib,"ws2_32.lib") void initialization(); int main() { //创建套接字 s_server = socket(AF_INET, SOCK_STREAM, 0); } void initialization() { //初始化套接字库 WORD w_req = MAKEWORD(2, 2);//版本号 WSADATA wsadata; int err; err = WSAStartup(w_req, &wsadata); if (err != 0) { cout << "初始化套接字库失败!" << endl; } else { cout << "初始化套接字库成功!" << endl; } //检测版本号 if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) { cout << "套接字库版本号不符!" << endl; WSACleanup(); } else { cout << "套接字库版本正确!" << endl; } //填充服务端地址信息 }

    (2)绑定套接字到一个IP地址和一个端口上(bind());

    server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(5010);

       (3)将套接字设置为监听模式等待连接请求(listen());

    //设置套接字为监听状态 if (listen(s_server, SOMAXCONN) < 0) { cout << "设置监听状态失败!" << endl; WSACleanup(); } else { cout << "设置监听状态成功!" << endl; } cout << "服务端正在监听连接,请稍候...." << endl;

       (4)请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());

    //接受连接请求 len = sizeof(SOCKADDR); s_accept = accept(s_server, (SOCKADDR *)&accept_addr, &len); if (s_accept == SOCKET_ERROR) { cout << "连接失败!" << endl; WSACleanup(); return 0; } cout << "连接建立,准备接受数据" << endl;

     (5)用返回的套接字和客户端进行通信(send()/recv());

    //接收数据 while (1) { recv_len = recv(s_accept, recv_buf, 100, 0); if (recv_len < 0) { cout << "接受失败!" << endl; break; } else { cout << "客户端信息:" << recv_buf << endl; } cout << "请输入回复信息:"; cin >> send_buf; send_len = send(s_accept, send_buf, 100, 0); if (send_len < 0) { cout << "发送失败!" << endl; break; } }

     (6)返回,等待另一个连接请求;

      (7)关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup());

    //关闭套接字 closesocket(s_server); closesocket(s_accept); //释放DLL资源 WSACleanup(); return 0;

     2、Client端

        (1)加载套接字库,创建套接字(WSAStartup()/socket);

    #include<winsock.h> #pragma comment(lib,"ws2_32.lib") void initialization(); int main() { //创建套接字 s_server = socket(AF_INET, SOCK_STREAM, 0); } void initialization() { //初始化套接字库 WORD w_req = MAKEWORD(2, 2);//版本号 WSADATA wsadata; int err; err = WSAStartup(w_req, &wsadata); if (err != 0) { cout << "初始化套接字库失败!" << endl; } else { cout << "初始化套接字库成功!" << endl; } //检测版本号 if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) { cout << "套接字库版本号不符!" << endl; WSACleanup(); } else { cout << "套接字库版本正确!" << endl; } //填充服务端地址信息 }

     (2)向服务器发出连接请求(connect());

    if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) { cout << "服务器连接失败!" << endl; WSACleanup(); } else { cout << "服务器连接成功!" << endl; }

    (3)和服务器进行通信(send()/recv());

    //发送,接收数据 while (1) { cout << "请输入发送信息:"; cin >> send_buf; send_len = send(s_server, send_buf, 100, 0); if (send_len < 0) { cout << "发送失败!" << endl; break; } recv_len = recv(s_server, recv_buf, 100, 0); if (recv_len < 0) { cout << "接受失败!" << endl; break; } else { cout << "服务端信息:" << recv_buf << endl; } }

     (4)关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())

    //关闭套接字 closesocket(s_server); //释放DLL资源 WSACleanup();

    五、Windows下基于VS2017实现的socket简单实例(TCP/IP)

    (1)server端代码

    #include "pch.h" #include<iostream> #include<winsock.h> #pragma comment(lib,"ws2_32.lib") using namespace std; void initialization(); int main() { //定义长度变量 int send_len = 0; int recv_len = 0; int len = 0; //定义发送缓冲区和接受缓冲区 char send_buf[100]; char recv_buf[100]; //定义服务端套接字,接受请求套接字 SOCKET s_server; SOCKET s_accept; //服务端地址客户端地址 SOCKADDR_IN server_addr; SOCKADDR_IN accept_addr; initialization(); //填充服务端信息 server_addr.sin_family = AF_INET; server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(5010); //创建套接字 s_server = socket(AF_INET, SOCK_STREAM, 0); if (bind(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) { cout << "套接字绑定失败!" << endl; WSACleanup(); } else { cout << "套接字绑定成功!" << endl; } //设置套接字为监听状态 if (listen(s_server, SOMAXCONN) < 0) { cout << "设置监听状态失败!" << endl; WSACleanup(); } else { cout << "设置监听状态成功!" << endl; } cout << "服务端正在监听连接,请稍候...." << endl; //接受连接请求 len = sizeof(SOCKADDR); s_accept = accept(s_server, (SOCKADDR *)&accept_addr, &len); if (s_accept == SOCKET_ERROR) { cout << "连接失败!" << endl; WSACleanup(); return 0; } cout << "连接建立,准备接受数据" << endl; //接收数据 while (1) { recv_len = recv(s_accept, recv_buf, 100, 0); if (recv_len < 0) { cout << "接受失败!" << endl; break; } else { cout << "客户端信息:" << recv_buf << endl; } cout << "请输入回复信息:"; cin >> send_buf; send_len = send(s_accept, send_buf, 100, 0); if (send_len < 0) { cout << "发送失败!" << endl; break; } } //关闭套接字 closesocket(s_server); closesocket(s_accept); //释放DLL资源 WSACleanup(); return 0; } void initialization() { //初始化套接字库 WORD w_req = MAKEWORD(2, 2);//版本号 WSADATA wsadata; int err; err = WSAStartup(w_req, &wsadata); if (err != 0) { cout << "初始化套接字库失败!" << endl; } else { cout << "初始化套接字库成功!" << endl; } //检测版本号 if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) { cout << "套接字库版本号不符!" << endl; WSACleanup(); } else { cout << "套接字库版本正确!" << endl; } //填充服务端地址信息 }

    (2)client端:

    #include "pch.h" #include<iostream> #include<winsock.h> #pragma comment(lib,"ws2_32.lib") using namespace std; void initialization(); int main() { //定义长度变量 int send_len = 0; int recv_len = 0; //定义发送缓冲区和接受缓冲区 char send_buf[100]; char recv_buf[100]; //定义服务端套接字,接受请求套接字 SOCKET s_server; //服务端地址客户端地址 SOCKADDR_IN server_addr; initialization(); //填充服务端信息 server_addr.sin_family = AF_INET; server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); server_addr.sin_port = htons(1234); //创建套接字 s_server = socket(AF_INET, SOCK_STREAM, 0); if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) { cout << "服务器连接失败!" << endl; WSACleanup(); } else { cout << "服务器连接成功!" << endl; } //发送,接收数据 while (1) { cout << "请输入发送信息:"; cin >> send_buf; send_len = send(s_server, send_buf, 100, 0); if (send_len < 0) { cout << "发送失败!" << endl; break; } recv_len = recv(s_server, recv_buf, 100, 0); if (recv_len < 0) { cout << "接受失败!" << endl; break; } else { cout << "服务端信息:" << recv_buf << endl; } } //关闭套接字 closesocket(s_server); //释放DLL资源 WSACleanup(); return 0; } void initialization() { //初始化套接字库 WORD w_req = MAKEWORD(2, 2);//版本号 WSADATA wsadata; int err; err = WSAStartup(w_req, &wsadata); if (err != 0) { cout << "初始化套接字库失败!" << endl; } else { cout << "初始化套接字库成功!" << endl; } //检测版本号 if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) { cout << "套接字库版本号不符!" << endl; WSACleanup(); } else { cout << "套接字库版本正确!" << endl; } //填充服务端地址信息 }

    注:对于入门级别学习的同学一些使用指导,想要让这俩程序跑起来,如果只有一台电脑,那么只需要在一台电脑上VS中创建两个不同的控制台应用程序,然后把server和client代码分别copy到这俩新建项目的主程序中,直接运行即可。

    六、运行结果显示

    (1)server端

    (2)client端

     

    感谢作者的分享!

    原文地址:https://blog.csdn.net/qq_27923041/article/details/83857964

    最新回复(0)