QT中使用C++ socket通信(了解socket通信、socket的三次握手和四次挥手、socket函数说明、客户端与服务端的代码实例)

6 篇文章 0 订阅

一、TCP/IP协议四个抽象层:

 

二、socket位置

socket就在应用程序的传输层和应用层之间,传输层的底一层的服务提供给socket抽象层,socket抽象层再提供给应用层。

三、socket三次握手:

第一次握手:客户端尝试连接服务器,向服务器发送syn包,

第二次握手:服务器接收客户端syn包并确认,同时向客户端发送一个SYN包,即SYN+ACK包

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK,此包发送完毕,完成三次握手,建立连接

四、socket四次挥手:

第一次挥手:某个应用进程首先调用closesocket主动关闭连接,这时主动方(客户端或者服务端)发送一个FIN;

第二次挥手:被动方接收到FIN之后,执行被动关闭,对这个FIN进行确认,发送ACK确认信号。

第三次挥手:一段时间之后,被动关闭的一方在完成所有数据发送后,调用close()操作。这导致它也发送一个FIN;

第四次挥手:主动方接收到这个FIN,向被动方发送ACK进行确认,一段时间后进入关闭状态。被动方接收之后,进入关闭状态。

这样每个方向上都有一个FIN和ACK。

五、socket基本操作

1. socket函数

int socket(int domain, int type, int protocol);

socket()用于创建一个socket的套接字,它唯一标识一个socket。后续的操作都有用到这个套接字,把它作为参数,通过它来进行一些读写操作。

参数:

domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL等;

type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET等等;

protocol:指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等。当protocol为0时,会自动选择type类型对应的默认协议。

2. bind函数

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。

参数:

sockfd:即socket套接字,它是通过socket()函数创建了,唯一标识一个socket;

addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址;

addrlen:对应的是地址的长度。

3. listen、connect函数

如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。

服务器:int listen(int sockfd, int backlog);

参数:

sockfd:要监听的socket套接字;

backlog:相应socket可以排队的最大连接个数。

客户端:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数:

sockfd:客户端的socket套接字;

addr:服务器的socket地址;

addrlen:socket地址的长度

4. accept函数

SOCKET accept(SOCKET sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数:

sockfd:服务器的socket描述字;

addr:指向struct sockaddr *的指针,用于返回客户端的协议地址;

addrlen:协议地址的长度;

accept函数返回的是已连接的socket套接字。

5. send函数

int send( SOCKET s, const char FAR *buf, int len, int flags );

不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。

参数:

s:指定发送端套接字描述符;

buf:指明一个存放应用程序要发送数据的缓冲区;

len:指明实际要发送的数据的字节数;

flags:一般置0。 

不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。

6. recv函数

int recv(SOCKET s,char *buf,int len,int flags);

参数:

s:接收端的套接字描述符;

buf:接收数据的缓冲区;

len:接收数据的字节数;

flags:一般置0。

7. closesocket函数

int closesocket(SOCKET s)

参数:

s:需要关闭的socket套接字。

六、代码实例:

在QT中使用之前需在.pro中添加socket库

LIBS += -lpthread libwsock32 libws2_32

服务端:

#include <QCoreApplication>
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //初始化套接字库
    WORD word = MAKEWORD(2,2);//版本号
    WSADATA wsadata;
    WSAStartup(word,&wsadata);
    //定义服务端套接字,接受请求套接字
    SOCKET serviceSocket;
    SOCKET clientSocket;
    //服务端地址,客户端地址
    SOCKADDR_IN socketAddr;
    SOCKADDR_IN clientAddr;
    //填充服务端信息
    socketAddr.sin_family = AF_INET;
    socketAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    socketAddr.sin_port = htons(10000);
    //创建套接字
    serviceSocket = socket(AF_INET, SOCK_STREAM, 0);
    //绑定套接字
    int bRes = bind(serviceSocket, (SOCKADDR*)&socketAddr, sizeof(SOCKADDR));	//绑定注意的一点就是记得强制类型转换
    if (SOCKET_ERROR == bRes)
    {
        cout << "Bind failure!" << endl;
    }
    else
    {
        cout << "Bind success!" << endl;
    }
    //设置套接字为监听状态
    int lLen = listen(serviceSocket, SOMAXCONN);
    if (SOCKET_ERROR == lLen)
    {
        cout << "Listen failure!" << endl;
        WSACleanup();
    }
    else
    {
        cout << "Listen success!" << endl;
    }
    cout << "The server is listening for connection, please wait!" << endl;
    //接受连接请求
    int revSize = sizeof(SOCKADDR);
    clientSocket = accept(serviceSocket, (SOCKADDR*)&clientAddr, &revSize);
    if (clientSocket == SOCKET_ERROR)
    {
        cout << "Accept connectionfailure!" << endl;
        WSACleanup();
        return 0;
    }
    cout << "Connection established, ready to receive data!" << endl;
    while (1)
    {
        char recvBuf[1024];
        int recv_len = recv(clientSocket,recvBuf,100,0);
        if (recv_len < 0)
        {
            cout << "Acceptfailure!" << endl;
            break;
        }
        else
        {
            cout << "Received client information:" << recvBuf << endl;
        }
        cout << "Please enter a reply message:";
        char sendBuf[1024];
        cin >> sendBuf;
        int send_len = send(clientSocket,sendBuf,strlen(sendBuf),0);
        if (send_len < 0)
        {
            cout << "Send failure!" << endl;
            break;
        }
    }
    //关闭socket
    closesocket(serviceSocket);

    //终止
    WSACleanup();


    return a.exec();
}

客户端:

#include <QCoreApplication>
#include <Windows.h>
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //初始化套接字库
    WORD word = MAKEWORD(2,2);//版本号
    WSADATA wsadata;
    WSAStartup(word,&wsadata);
    //定义客户端套接字
    SOCKET clientSocket;
    //服务端地址
    SOCKADDR_IN socketAddr;
    //填充服务端信息
    socketAddr.sin_family = AF_INET;
    socketAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    socketAddr.sin_port = htons(10000);
    //创建套接字
    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    //连接服务器
    int ret = connect(clientSocket, (SOCKADDR*)&socketAddr, sizeof(SOCKADDR));
    if(ret == SOCKET_ERROR)
    {
        cout << "Connect failure!" << endl;
        WSACleanup();
    }
    else
    {
        cout << "Connect success!" << endl;
    }
    //发送数据
    while (1)
    {
        char sendBuf[1024];
        cout << "Please enter send information:" << endl;
        cin >> sendBuf;
        int sendLen = send(clientSocket, sendBuf, 100, 0);
        if (sendLen < 0)
        {
            cout << "Send success!" << endl;
            break;
        }
        char recvBuf[100];
        int recvLen = recv(clientSocket,recvBuf,100,0);
        if (recvLen < 0)
        {
            cout << "Send failure!" << endl;
            break;
        }
        else
        {
            cout << "Received server information:" << recvBuf << endl;
        }
    }
    //关闭套接字
    closesocket(clientSocket);
    //释放DLL资源
    WSACleanup();

    return a.exec();
}

  • 8
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值