鸦领主 发表于 2021-2-21 15:23:15

C++ TCP通讯流程 创建线程

1、tcp与udp的对比:
a)TCP是面向连接的传输控制协议,而UDP提供了无连接的数据报服务;
b)TCP具有高可靠性,确保传输数据的正确性,不出现丢失或乱序;.(不丢失不乱序)
UDP在传输数据前不建立连接,不对数据报进行检查与修改,无须等待对方的应答,
所以会出现分组丢失、重复、乱序,应用程序需要负责传输可靠性方面的所有工作;
(就算网络是正常的仍然不排除丢包的现象,不会丢半个包要丢就是一个包)
(可能丢包可能包与包的顺序先发的后到出现混乱)
c)也,正因为以上特征,UDP具有较好的实时性,工作效率较TCP协议高;
d)UDP段结构比TCP的段结构简单,因此网络开销也小。

2、TCP通讯流程:
接收端:
WSAStartup:初始化操作
socket:建立套接字
bind:绑定
listen:开始侦听
accept:接纳客户端连接(如同公司的前台)
send/recv/recvfrom:收发数据(如同公司的客户经理)
发送端:
WSAStartup:初始化操作
socket:建立套接字
bind:绑定
connect:连接
send/recv/recvfrom:收发数据(如同公司的客户经理)
=

接收端:
#include<Winsock.h>
#include<iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main()
{
    WSADATA ws;
    WSAStartup(0x0202, &ws); //连接
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);//创建套接字
    sockaddr_in sa = { 2 ,htons(3000)};
    bind(sock, (sockaddr*)&sa, sizeof(sa));//绑定
    listen(sock, 5);//监听
    int nLen = sizeof(sa);
    char c = { 0 };
    while (true)
    {
      SOCKET socka = accept(sock, (sockaddr*)&sa, &nLen);//接待//后面俩个参数是将连接到的发送端的ip和端口记录下来,不录就填NULL
    while (true)
    {
       // getpeername(socka, (sockaddr*)&sa, &nLen);//获取发送端信息ip和端口
      int n = recv(socka, c, sizeof(c), 0);//收发数据
      cout << inet_ntoa(sa.sin_addr) << "-" << htons(sa.sin_port) <<":"<< c << endl;
    }
    }
    return 0;
}发送端:
#include<Winsock.h>
#include<iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main()
{
    WSADATA ws;
    WSAStartup(0x0202, &ws); //连接
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);//创建套接字
    sockaddr_in sa = { 2 };
    int n=bind(sock, (sockaddr*)&sa, sizeof(sa));//绑定
    sa.sin_port = htons(3000);
    sa.sin_addr.S_un.S_addr = inet_addr("192.168.1.9");
    connect(sock, (sockaddr*)&sa, sizeof(sa));//连接到接收端
    char c = {0};
    while (true)
    {
      cout << "请输入:";
      cin >> c;
      n=send(sock, c, strlen(c), 0);//收发数据
    }
    return 0;
}

3.创建线程
_beginthread()需要#include<process.h>//创建线程函数
uintptr_t _beginthread(    void( __cdecl *start_address )( void * ),   unsigned stack_size,   void *arglist   );
第一个参数:
start_address为启动开始执行新线程的例程的地址,一般我们执行一个函数,这个参数就是你定义的函数名(这个函数就是一个新线程)。
第二个参数:
stack_size,新线程的堆栈大小或 0。一般我们使用0,代表跟主线程使用一样的堆栈。
第三个参数:
arglist,要传递到新线程的参数列表或 NULL。如果你要传递参数给新的线程,可以在这里写上参数的地址指针,如果不需要传递数据,就使用NULL。void Thread(void* p)//创建一个新线程就等价于创建一个main函数,而这个就相当于main函数
{
        SOCKET* psock = (SOCKET*)p;//void是接受任何类型的,当使用需要强制转换一下
        SOCKET socka = *psock;//psock的内容赋值给一个新的socka,如果不这样做那么。有多个线程的化,他们将指向同一个sock
        sockaddr_in sa = { AF_INET };
        int nLen = sizeof(sa);
        char c = { 0 };
        while (true)
        {
                getpeername(socka, (sockaddr*)&sa, &nLen);//获取发送端信息ip和端口
                int n = recv(socka, c, sizeof(c), 0);//收发数据
                if (n <= 0)
                {
                        cout << inet_ntoa(sa.sin_addr) << "-" << htons(sa.sin_port) << "断开连接!" << endl;
                        break;
                }
                cout << inet_ntoa(sa.sin_addr) << "-" << htons(sa.sin_port) <<":"<< c << endl;
        }
}

int main()
{
        WSADATA ws;
        WSAStartup(0x0202, &ws); //连接
        SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);//创建套接字
        sockaddr_in sa = { 2 ,htons(3000)};
        bind(sock, (sockaddr*)&sa, sizeof(sa));//绑定
        listen(sock, 5);//监听
        int nLen = sizeof(sa);
        while (true)
        {
                SOCKET socka = accept(sock, (sockaddr*)&sa, &nLen);//接待//后面俩个参数是将连接到的发送端的ip和端口记录下来,不记录就填NULL
                _beginthread(Thread, 0, &socka);//带入函数名(新线程),0,再将socka带进来,因为要再新线程里面进行接收数据,当
//有俩个客户端连接进来就会创建俩个线程同时接收信息
                cout << inet_ntoa(sa.sin_addr) << "-" << htons(sa.sin_port) << "连接成功!" << endl;
        }
        return 0;
}




1595 发表于 2021-4-10 23:36:04

感谢分享

玄之玄 发表于 2021-4-12 16:53:17

感谢分享

xiaoweiwb 发表于 2021-9-13 05:41:11

学习了,谢谢

xiaoweiwb 发表于 2021-11-27 07:52:28

谢谢分享谢谢分享
页: [1]
查看完整版本: C++ TCP通讯流程 创建线程