C语言 Socket TCP通信

C语言 Socket TCP通信TCP简介传输控制协议(TCP)是一种网络通信协议,旨在通过Internet发送数据包。TCP是OSI层中的传输层协议,用于通过传输和确保通过支持网络和Internet传递消息来在远程计算机之间创建连接。

大家好,又见面了,我是你们的朋友全栈君。

基础知识

TCP

传输控制协议(TCP)是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议,位于传输层,旨在通过Internet发送报文。

Socket(套接字)

套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作,实际上是一个指向传输提供者的句柄。在WinSock中,就是通过操作该句柄来实现网络通信和管理的。

IP

IP是Internet Protocol(网际互连协议)的缩写,是TCP/IP体系中的网络层协议。为了使网络上的计算机能够彼此识别对方,每台计算机都需要一个IP来标识自己。

端口

端口可以认为是设备与外界通讯交流的出口。在网络上,计算机通过IP来找到对方,而应用程序则通过绑定端口来标识通讯的应用程序。

TCP通讯的基本流程

在这里插入图片描述

代码编写

服务端

tcp_server.c

#include <stdio.h>
#include <WinSock2.h>

#define version_h 2
#define version_l 2
#define DEFAULT_BUFLEN 512
int main()
{ 
   
    //1.初始化套接字库

    //高位字节指定次要版本号;低位字节指定主版本号。
    WORD wVersionRequested = MAKEWORD(version_h, version_l);
    WSADATA wsaData;

    int error = WSAStartup(wVersionRequested, &wsaData);

    if (errno != 0)
    { 
   
        printf("Cant initiates use of the Winsock DLL by a process!\n");
        return 1;
    }

    //确认WinSock DLL支持2.2,如果DLL支持更高版本,它依然返回2.2
    if (LOBYTE(wsaData.wVersion) != version_l ||
        HIBYTE(wsaData.wVersion) != version_h)
    { 
   
        /* 找不到可用的WinSock DLL */
        printf("could not find a usable WinSock DLL!\n");
        WSACleanup();
        return 1;
    }

    //2.创建套接字
    SOCKADDR_IN server_address;

    //The address family for the transport address. This member should always be set to AF_INET.
    server_address.sin_family = AF_INET;
    //An IN_ADDR structure that contains an IPv4 transport address.
    server_address.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    //A transport protocol port number.
    server_address.sin_port = htons(5000);
    //申请套接字
    SOCKET socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (INVALID_SOCKET == socket_server)
    { 
   
        wprintf(L"socket function failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    //3.绑定套接字到本地的某个地址和端口
    if (SOCKET_ERROR == bind(socket_server, (SOCKADDR *)&server_address, sizeof(server_address)))
    { 
   
        wprintf(L"bind failed with error %u\n", WSAGetLastError());
        closesocket(socket_server);
        WSACleanup();
        return 1;
    }

    wprintf(L"bind returned success\n");

    //4.监听客户端
    if (SOCKET_ERROR == listen(socket_server, 1))
        wprintf(L"listen function failed with error: %d\n", WSAGetLastError());

    wprintf(L"Listening on socket...\n");

    //5.接受客户端连接
    SOCKADDR_IN client_address;
    int address_length=sizeof(client_address);
    SOCKET socket_client = accept(socket_server, (SOCKADDR *)&client_address, &address_length);
    if (INVALID_SOCKET == socket_client)
        wprintf(L"accept failed with error: %ld\n", WSAGetLastError());
    wprintf(L"connect client success\n");
    //6.进行会话
    char send_buff[DEFAULT_BUFLEN] = "I receive your message!";
    char recv_buff[DEFAULT_BUFLEN] = { 
   0};

    while (1)
    { 
   
        int ret = recv(socket_client, recv_buff, DEFAULT_BUFLEN, 0);
        if (ret > 0)
            printf("Receive from Client: %s\n", recv_buff);
        else
        { 
   
            if (0 == ret)
            { 
   
                printf("Connection closed\n");
                break;
            }
            else
            { 
   
                printf("recv failed: %d\n", WSAGetLastError());
                closesocket(socket_client);
                closesocket(socket_server);
                WSACleanup();
                return 1;
            }
        }
        ret = send(socket_client, send_buff,DEFAULT_BUFLEN, 0);
        if (SOCKET_ERROR == ret)
        { 
   
            wprintf(L"send failed with error: %d\n", WSAGetLastError());
            closesocket(socket_client);
            closesocket(socket_server);
            WSACleanup();
            return 1;
        }
    }

    //7.关闭套接字
    if (SOCKET_ERROR == closesocket(socket_client))
    { 
   
        wprintf(L"closesocket function failed with error %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    if (SOCKET_ERROR == closesocket(socket_server))
    { 
   
        wprintf(L"closesocket function failed with error %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    WSACleanup();
    return 0;
}

客服端

tcp_client.c

#include <stdio.h>
#include <WinSock2.h>

#define version_h 2
#define version_l 2
#define DEFAULT_BUFLEN 512
int main()
{ 
   
    //1.初始化套接字库

    //高位字节指定次要版本号;低位字节指定主版本号。
    WORD wVersionRequested = MAKEWORD(version_h, version_l);
    WSADATA wsaData;

    int error = WSAStartup(wVersionRequested, &wsaData);

    if (errno != 0)
    { 
   
        printf("Cant initiates use of the Winsock DLL by a process!\n");
        return 1;
    }

    //确认WinSock DLL支持2.2,如果DLL支持更高版本,它依然返回2.2
    if (LOBYTE(wsaData.wVersion) != version_l ||
        HIBYTE(wsaData.wVersion) != version_h)
    { 
   
        /* 找不到可用的WinSock DLL */
        printf("could not find a usable WinSock DLL!\n");
        WSACleanup();
        return 1;
    }

    //2.创建套接字
    SOCKADDR_IN server_address;

    //The address family for the transport address. This member should always be set to AF_INET.
    server_address.sin_family = AF_INET;
    //An IN_ADDR structure that contains an IPv4 transport address.
    server_address.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    //A transport protocol port number.
    server_address.sin_port = htons(5000);
    //申请套接字
    SOCKET socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (INVALID_SOCKET == socket_server)
    { 
   
        wprintf(L"socket function failed with error: %ld\n", WSAGetLastError());
        getchar();
        WSACleanup();
        return 1;
    }
    //3.连接服务器
    if(SOCKET_ERROR==connect(socket_server, (SOCKADDR *)&server_address, sizeof(server_address)))
    { 
   
        wprintf(L"connect function failed with error: %ld\n", WSAGetLastError());
        getchar();
        closesocket(socket_server);
        WSACleanup();
        return 1;
    }
    wprintf(L"Connected to server.\n");

    //4.进行会话
    int recv_ret;
    int send_ret;
    char send_buff[DEFAULT_BUFLEN] ={ 
   0};
    char recv_buff[DEFAULT_BUFLEN] = { 
   0};

    while (1)
    { 
   
        printf("You send:");
        gets(send_buff);
        send_ret = send(socket_server, send_buff,DEFAULT_BUFLEN, 0);
        if (SOCKET_ERROR == send_ret)
        { 
   
            wprintf(L"send failed with error: %d\n", WSAGetLastError());
            getchar();
            closesocket(socket_server);
            WSACleanup();
            return 1;
        }

        int ret = recv(socket_server, recv_buff, DEFAULT_BUFLEN, 0);
        if (ret > 0)
            printf("Receive from Server: %s\n", recv_buff);
        else
        { 
   
            if (0 == ret)
            { 
   
                printf("Connection closed\n");
                break;
            }
            else
            { 
   
                printf("recv failed: %d\n", WSAGetLastError());
                getchar();
                closesocket(socket_server);
                WSACleanup();
                return 1;
            }
        }
    }

    //5.关闭套接字
    if (SOCKET_ERROR == closesocket(socket_server))
    { 
   
        wprintf(L"closesocket function failed with error %d\n", WSAGetLastError());
        getchar();
        WSACleanup();
        return 1;
    }

    WSACleanup();
    return 0;
}

windows编译脚本

因为本人是用gcc编译的

complie.bat

gcc -g .\tcp_client.c -o .\tcp_client -lws2_32

gcc -g .\tcp_server.c -o .\tcp_server -lws2_32

pause

执行效果

在这里插入图片描述

总结

错误判断可能有点多,不过出错后可以更容易的发现错误并解决

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/158482.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 用Python读取CSV文件的5种方式

    用Python读取CSV文件的5种方式典型的数据集stocks.csv:一个股票的数据集,其实就是常见的表格数据。有股票代码,价格,日期,时间,价格变动和成交量。这个数据集其实就是一个表格数据,有自己的头部和身体。第一招:简单的读取我们先来看一种简单读取方法,先用csv.reader()函数读取文件的句柄f生成一个csv的句柄,其实就是一个迭代器,我们看一下这个reader的源码:喂给reader一个可迭代对象或者是文件的object,然后返回一个可迭代对象。首先读取csv文件,然后用csv.reader生成一个csv迭代器

    2022年7月21日
  • 设置matlab保存的图片没有白边,matlab如何保存figure中去掉白边的图片「建议收藏」

    设置matlab保存的图片没有白边,matlab如何保存figure中去掉白边的图片「建议收藏」输出图片成可直接调入的灰度图,设置输出图片空白边距,以及调整图片大小,纵横比。一、先显示图片,imshow。如果是plot,或者newplot,直接看“三”。imshow(strain_image,’border’,’tight’,’initialmagnification’,’fit’);%’border’,’tight’的组合功能意思是去掉图像周边空白%’InitialMagnificatio…

    2022年9月3日
  • wJa丨Java闭源项目的自动化测试「建议收藏」

    wJa丨Java闭源项目的自动化测试「建议收藏」本文是i春秋论坛作家「Wker」表哥分享的技术文章,文章旨在为大家提供更多的学习方法与技能技巧,文章仅供学习参考。wJa支持反编译Java生成的jar包文件,整理成语法树,根据调用链进行污点分析

    2022年7月3日
  • selenium+webdriver_python爬虫安装

    selenium+webdriver_python爬虫安装1、下载地址:https://chromedriver.chromium.org/downloads根据谷歌浏览器的版本选择地址,一定要选择对应的版本,选择错误无法运行程序。如果找不到对应的版本,可以把谷歌浏览器更新到最新的版本,然后下载页面第一个程序(最新)2、安装步骤①将下载到的文件解压,应当只有一个EXE文件②将该文件拷贝一份放到谷歌浏览器目录下,找到快捷方式【打开所在目录】即可③将该文件再拷贝一份放到Python编译器目录下如图2所示。图1将文件放到谷歌浏览器目录下图2将文

    2022年9月19日
  • 文件读取(FileInputStream 读取本地文件)

    文件读取(FileInputStream 读取本地文件)使用FileInputStream读取本地文件(图片、视频、音乐、文档资料)二进制文件、文本文件1.在物理存储上上没有什么区别,存在硬盘上都是以二进制方式存储2.解释数据的逻辑不同,程序读取文本文件,可以以字符方式读取,也可以以字节读取,将读取的数据解释为ASCII或者unicode编码;当程序读取二进制文件,以字节方式读取,对读取数据的解释由读取数据而定,如读取图片时,需要了解文件的结…

    2022年5月26日
  • arm Linux_arch linux

    arm Linux_arch linux/* * __flush_dcache_all()* FlushthewholeD-cache. * Corruptedregisters:x0-x7,x9-x11 */ENTRY(__flush_dcache_all)//保证之前的访存指令的顺序   dsbsy                 //读cachelevelidregi

    2022年10月8日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号