C语言实现TCP通信

2023-05-16

C语言通过socket编程实现TCP通信

服务端客户端通信例子:socket tcp 通信1,socket tcp通信2,udp使用讲解,socket udp通信例子

  1. TCP/IP协议

叫做传输控制/网际协议,又叫网络通信协议。实际上,它包含上百个功能的协议,如ICMP(互联网控制信息协议)、FTP(文件传输协议)、UDP(用户数据包协议)、ARP(地址解析协议)等。TCP负责发现传输的问题,一旦有问题就会发出重传信号,直到所有数据安全正确的传输到目的地。

2.套接字(socket):

在网络中用来描述计算机中不同程序与其他计算机程序的通信方式。socket其实是一种特殊的IO接口,也是一种文件描述符。

套接字分为三类:

流式socket(SOCK_STREAM):流式套接字提供可靠、面向连接的通信流;它使用TCP协议,从而保证了数据传输的正确性和顺序性。

数据报socket(SOCK_DGRAM):数据报套接字定义了一种无连接的服务,数据通过相互独立的保温进行传输,是无序的,并且不保证是可靠、无差错的。它使用的数据报协议是UDP。

原始socket:原始套接字允许对底层协议如IP或ICMP进行直接访问,它功能强大但使用复杂,主要用于一些协议的开发。

套接字由三个参数构成:IP地址,端口号,传输层协议。这三个参数用以区分不同应用程序进程间的网络通信与连接。

套接字的数据结构:C语言进行套接字编程时,常会使用到sockaddr数据类型和sockaddr_in数据类型,用于保存套接字信息。

两种结构体分别表示如下:

struct sockaddr
{
 
//地址族,2字节
unsigned short sa_family;
 
//存放地址和端口,14字节
char sa_data[14];
 
}
 
 
struct sockaddr_in
{
 
//地址族
short int sin_family;
 
//端口号(使用网络字节序)
unsigned short int sin_port;
 
//地址
struct in_addr sin_addr;
 
//8字节数组,全为0,该字节数组的作用只是为了让两种数据结构大小相同而保留的空字节
unsigned char sin_zero[8]
 
}

对于sockaddr,大部分的情况下只是用于bind,connect,recvfrom,sendto等函数的参数,指明地址信息,在一般编程中,并不对此结构体直接操作。而用sockaddr_in来替。

两种数据结构中,地址族都占2个字节,

常见的地址族有:AF_INET,AF_INET6AF_LOCAL。

这里要注意字节序的问题,最好使用以下函数来对端口和地址进行处理:

  1. uint16_t htons(uint16_t host16bit) 把16位值从主机字节序转到网络字节序

    uint32_t htonl(uint32_t host32bit) 把32位值从主机字节序转到网络字节序

  2. uint16_t ntohs(uint16_t net16bit) 把16位值从网络字节序转到主机字节序

    uint32_t ntohs(uint32_t net32bit) 把32位值从网络字节序转到主机字节序

使用socket进行TCP通信时,经常使用的函数有:

3.下面给出server和client的两个例子

更详细的例子

服务端:

/socket tcp服务器端/

#include <sys/stat.h>
 
#include <fcntl.h>
 
#include <errno.h>
 
#include <netdb.h>
 
#include <sys/types.h>
 
#include <sys/socket.h>
 
#include <netinet/in.h>
 
#include <arpa/inet.h>
 
#include <stdio.h>
 
#include <string.h>
 
#include <stdlib.h>
 
#include <unistd.h>
 
#define SERVER_PORT 6666
 
/*
监听后,一直处于accept阻塞状态,
直到有客户端连接,
当客户端如数quit后,断开与客户端的连接
*/
 
int main()
 
{
 
//调用socket函数返回的文件描述符
 
int serverSocket;
 
//声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器
 
struct sockaddr_in server_addr;
 
struct sockaddr_in clientAddr;
 
int addr_len = sizeof(clientAddr);
 
int client;
 
char buffer[200];
 
int iDataNum;
 
//socket函数,失败返回-1
 
//int socket(int domain, int type, int protocol);
 
//第一个参数表示使用的地址类型,一般都是ipv4,AF_INET
 
//第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM
 
//第三个参数设置为0
 
if((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 
{
 
perror("socket");
 
return 1;
 
}
 
bzero(&server_addr, sizeof(server_addr));
 
//初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序
 
server_addr.sin_family = AF_INET;
 
server_addr.sin_port = htons(SERVER_PORT);
 
//ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址
 
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 
//对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)
 
//bind三个参数:服务器端的套接字的文件描述符,
 
if(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
 
{
 
perror("connect");
 
return 1;
 
}
 
//设置服务器上的socket为监听状态
 
if(listen(serverSocket, 5) < 0)
 
{
 
perror("listen");
 
return 1;
 
}
 
while(1)
 
{
 
printf("监听端口: %d\n", SERVER_PORT);
 
//调用accept函数后,会进入阻塞状态
 
//accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,
 
//serverSocket和client。
 
//serverSocket仍然继续在监听状态,client则负责接收和发送数据
 
//clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号
 
//addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。
 
//传出的是客户端地址结构体的实际长度。
 
//出错返回-1
 
client = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
 
if(client < 0)
 
{
 
perror("accept");
 
continue;
 
}
 
printf("等待消息...\n");
 
//inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP
 
//表达式:char *inet_ntoa (struct in_addr);
 
printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));
 
printf("Port is %d\n", htons(clientAddr.sin_port));
 
while(1)
 
{
 
printf("读取消息:");
 
buffer[0] = '\0';
 
iDataNum = recv(client, buffer, 1024, 0);
 
if(iDataNum < 0)
 
{
 
perror("recv null");
 
continue;
 
}
 
buffer[iDataNum] = '\0';
 
if(strcmp(buffer, "quit") == 0)
 
break;
 
printf("%s\n", buffer);
 
 
 
printf("发送消息:");
 
scanf("%s", buffer);
 
printf("\n");
 
send(client, buffer, strlen(buffer), 0);
 
if(strcmp(buffer, "quit") == 0)
 
break;
 
}
 
}
 
close(serverSocket);
 
return 0;
 
}

客户端:

/socket tcp客户端/

#include <sys/stat.h>
 
#include <fcntl.h>
 
#include <errno.h>
 
#include <netdb.h>
 
#include <sys/types.h>
 
#include <sys/socket.h>
 
#include <netinet/in.h>
 
#include <arpa/inet.h>
 
#include <stdio.h>
 
#include <string.h>
 
#include <stdlib.h>
 
#include <unistd.h>
 
#define SERVER_PORT 6666
 
/*
连接到服务器后,会不停循环,等待输入,
输入quit后,断开与服务器的连接
*/
 
int main()
 
{
 
//客户端只需要一个套接字文件描述符,用于和服务器通信
 
int clientSocket;
 
//描述服务器的socket
 
struct sockaddr_in serverAddr;
 
char sendbuf[200];
 
char recvbuf[200];
 
int iDataNum;
 
if((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 
{
 
perror("socket");
 
return 1;
 
}
 
serverAddr.sin_family = AF_INET;
 
serverAddr.sin_port = htons(SERVER_PORT);
 
//指定服务器端的ip,本地测试:127.0.0.1
 
//inet_addr()函数,将点分十进制IP转换成网络字节序IP
 
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
 
if(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
 
{
 
perror("connect");
 
return 1;
 
}
 
printf("连接到主机...\n");
 
while(1)
 
{
 
printf("发送消息:");
 
scanf("%s", sendbuf);
 
printf("\n");
 
send(clientSocket, sendbuf, strlen(sendbuf), 0);
 
 
 
if(strcmp(sendbuf, "quit") == 0)
 
break;
 
printf("读取消息:");
 
recvbuf[0] = '\0';
 
iDataNum = recv(clientSocket, recvbuf, 200, 0);
 
recvbuf[iDataNum] = '\0';
 
printf("%s\n", recvbuf);
 
}
 
close(clientSocket);
 
return 0;
 
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言实现TCP通信 的相关文章

  • C# Socket.receive连续接收0字节且循环中不阻塞

    我正在尝试用 C 编写一个最简单的多线程 TCP 服务器 它接收来自多个客户端的数据 每次连接新客户端时 都会建立套接字连接 并将套接字作为参数传递给新类函数 之后运行 while 循环并接收数据 直到客户端连接为止 这里的问题是 sock
  • 自动打开命名管道和 tcp\ip

    我正在安装一个需要修改 SQL Server 的新产品 具体来说 启用 tcp ip 并打开命名管道 我知道如何手动完成 我想要的是一种通过 SQL 或 C 代码为新客户自动化执行此操作的方法 我希望有任何关于正确方向的建议 您可以使用 C
  • 简单的跨平台 TCP IP API?

    我不打算使用像 QT 或 wxWidgets 的 API 这样的大东西 我只想要可以在 Android iOS Windows Mac Linux 上运行的简单套接字 我正在制作一个事件驱动的纸牌游戏 所以 TCP 是最好的 本质上 我只想
  • 为什么 UDP 服务器中只有一个套接字?

    我正在准备考试 发现了这个问题 典型的 UDP 服务器可以使用单个套接字来实现 解释一下为什么 对于 TCP 驱动的服务器 我发现创建了两个套接字 一个用于所有客户端访问服务器 另一个用于每个客户端的特定 套接字 用于服务器和客户端之间的进
  • 为什么我收到的数据包数据大小大于mss?

    我在两台 PC 上使用 ifconfig ethX mtu 300 修改了 MTU 并使用 netperf 测试网络 我用 WireShark 嗅探了 SYN 数据包中的 MSS 260 但我得到了一些大于 260 的数据包 为什么 嗅探器
  • 当使用环回地址使用 TCP/IP 套接字进行 IPC 时,常见的网络堆栈是否会跳过将消息帧封装在较低级别的 PDU 中?

    在某些环境 例如 Java 中 很自然地使用 TCP IP 套接字通过 localhost 地址 IPv4 中的 127 0 0 1 或 IPv6 中的 1 在同一主机上的进程之间传递消息 因为Java倾向于不在其API中公开其他IPC机制
  • 当 TCP 序列号到达而不是预期时会发生什么情况?

    我正在编写一个程序 使用 libpcap 捕获数据包并重新组装 TCP 流 我的程序只是监视流量 因此我无法控制数据包的接收和发送 我的程序忽略所有非 TCP IP 流量 我根据 ISN 计算下一个预期序列号 然后计算连续的 SEQ 号 我
  • 如何使用 Nmap 检索 TCP 和 UDP 端口? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我需要在使用 Nmap 的同一扫描中以尽可能最快的方式检索 TCP 和 UDP 端口 我会尽力解释得更好 如果我使用最常用的命令 nmap 192 1
  • 为什么tcp终止需要4次握手?

    当连接建立时 有 客户端 SYN gt 服务器 客户端 客户端 ACK gt 服务器 当终止到来时 有 客户端 FIN gt 服务器 客户端 客户端 客户端 ACK gt 服务器 我的问题是为什么 和 不能像 那样设置在同一个包中 即ACK
  • ADB TCPIP 连接问题

    我有两台 Galaxy S3 其中一个已扎根 另一个则未扎根 因此 当我尝试通过本地网络连接它们时 计算机可以看到已root的计算机 但是正常的就卡在tcpip这一步了 所以 我写 adb tcpip 5555 It says restar
  • 将 C++ TCP/IP 应用程序从 IPv4 转换为 IPv6。难的?值得这么麻烦吗?

    多年来 我使用 WinSock 为 Windows 开发了少量 C 服务器 客户端应用程序 路由器 Web 邮件 FTP 服务器等 等等 我开始越来越多地考虑创建这些应用程序的 IPv6 版本 当然 同时也保留原始的 IPv4 版本 问题
  • 了解 netty 通道缓冲区和水印

    我正在尝试了解网络缓冲区和水印 作为一个测试用例 我有一个 netty 服务器 它向客户端写入数据 客户端被阻止 基本上每次读取之间有 10 秒的睡眠时间 在正常 I O 下 如果接收方被阻塞 TCP 发送方将受到限制 由于流量控制 发送速
  • 立即检测客户端与服务器套接字的断开连接

    如何检测客户端已与服务器断开连接 我的代码中有以下代码AcceptCallBack method static Socket handler null public static void AcceptCallback IAsyncResu
  • C#:如何在 Socket.BeginReceive 回调之前终止套接字?

    我有一个接收来自客户端的连接请求的服务器 该服务器使用异步Socket BeginReceive and Socket EndReceive方法 该代码与找到的代码非常相似here http msdn microsoft com en us
  • TCP 连接寿命

    客户端 服务器 TCP 连接在野外可以持续多长时间 我希望它保持永久连接 但事情发生了 所以客户端将不得不重新连接 我什么时候可以说代码有问题而不是某些外部设备有问题 我同意赞 林克斯的观点 虽然无法保证 但假设不存在连接或带宽问题 您可以
  • 无法从亚马逊Windows实例的公共IP访问node.js服务器

    我正在 Windows 服务器的亚马逊微实例上运行 Node js 服务器 我无法使用亚马逊实例的公共IP访问node js服务器 我可以使用 localhost 12345 从实例访问 node js 服务器 但无法使用实例的公共 IP
  • TCP 中推送标志和紧急标志之间的区别

    我试图理解带有标志的 TCP 段之间的区别PSH和旗帜URG 我阅读了 RFC 但仍然无法获取它 其中一个在将数据发送到进程之前是否缓冲数据 而另一个则没有 它们是两种截然不同的机制 PSH 和 PUSH 函数 当您发送数据时 您的TCP缓
  • Silverlight 套接字:模仿框架 Bind、Listen 和 Accept 方法?

    我有这个 NET Framework C 类 它实际上充当 TCP 连接的包装器Socket http msdn microsoft com en us library attbb8f5 aspxSystem Net Sockets 命名空
  • 使用 NestJS 的 TCP 服务器

    是否可以使用 NestJS 创建 TCP 服务器 我有一个仅通过 TCP 进行通信的 GPS 跟踪器 由于 NestJS 可以通过 TCP 在微服务之间进行通信 我认为也许 NestJS 可以用作低级网络应用程序 例如 java netty
  • 在本地主机上使用相同的 IP 和端口创建套接字

    我在 Linux 上看到奇怪的行为 我看到远程端和本地端都显示相同的 IP 和端口组合 以下是 netstat 输出 netstat anp 网络统计grep 6102 tcp 0 0 139 185 44 123 61020 0 0 0

随机推荐

  • 拉流推流服务器设计

    背景 该服务器也是基于一个客户的需求产生的 客户那边使用的是腾讯的直播sdk xff0c 将不同终端的流推到腾讯云平台 xff0c 但是又想推到其他平台 xff0c 基于此需求 xff0c 该产品产生了 该产品通讯协议使用的是WebSock
  • 开发实现C++ RTMP直播推流sdk

    前言 rtmp即Real Time Messaging Protocol xff08 实时消息传输协议 xff09 的首字母缩写 xff0c 它是由Adobe公司提出的一种应用层的协议 xff0c 用来解决多媒体数据传输流的多路复用 xff
  • 开发实现C++ RTMP直播拉流播放器

    背景 该直播播放器的背景是来源于 拉流推流服务器设计 的一个分支 xff0c 它的重点是把拉下来的流进行解码显示播放 设计点 要实现跨平台 xff0c 目前支持的平台linux和windows要模块化和结构化可以拉各个平台的直播流要音视频同
  • 校验和计算原理

    校验和思路 首先 xff0c IP ICMP UDP和TCP报文头都有检验和字段 xff0c 大小都是16bit xff0c 算法基本上也是一样的 在发送数据时 xff0c 为了计算数据包的检验和 应该按如下步骤 xff1a 1 把校验和字
  • gb 28181的20位编码简介

    图解Python数据结构与算法 实战篇 举例 xff1a 36030000042000000003 设备的20位编码组成 国标编码由中心编码 xff08 8位 xff09 行业编码 xff08 2位 xff09 类型编码 xff08 3位
  • 继承的构造析构函数&&父类子类同名函数,变量的调用

    include lt iostream gt include 34 string 34 using namespace std class Base public int m A int m B 61 20 Base m A 61 100
  • CMake 之静态库依赖动态库,如何使用该静态库

    参考 xff1a xff08 参考文章用的Makefile 我自己用的CMake xff09 静态库链接动态库时 xff0c 如何使用该静态库 newchenxf的专栏 CSDN博客 链接静态库 1 先建立如下工程目录文件 下载 xff08
  • 单片机堆栈小知识

    目录 一 关于单片机堆栈的基础知识 1 STM32程序数据分类 2 STM32内存 RAM 分配 3 经典例子分析 xff1a 4 STM32堆栈位置 5 STM32栈增长方式 三 如何设置STM32的堆栈大小 1 MDK编译环境下 2 I
  • 要点初见:用Python进行微观交通模型仿真——基于SUMO的伯克利开源项目Flow Project初探与拓展

    后续拓展 xff1a 要点初见 xff1a 安装教程与二度拓展 基于SUMO的Flow Project xff08 附代码链接 xff09 通俗来讲 xff0c 微观交通模型仿真就是从车辆个体的视角 xff08 看动画 xff09 进行交通
  • 要点初见:安装教程与二度拓展——基于SUMO的Flow Project(附代码链接)

    前文链接 xff1a 要点初见 xff1a 用Python进行微观交通模型仿真 基于SUMO的伯克利开源项目Flow Project初探与拓展 前文链接中是博主先前写TRB论文时根据个人研究所写的Flow Project介绍 代码解释以及初
  • 要点初见:开源AI绘画工具Stable Diffusion代码分析(文本转图像)、论文介绍(上)

    博主先前整理并简单介绍了AI绘图工具的部署资源与攻略 xff0c 觉得其中Stable Diffusion部分不够带劲 xff0c 故开始试图从论文与代码中一探究竟 前文链接如下 xff1a 要点初见 xff1a AI绘图工具的部署资源 攻
  • 要点初见:开源AI绘画工具Stable Diffusion代码分析(文本转图像)、论文介绍(下)

    前文链接如下 xff1a 要点初见 xff1a 开源AI绘画工具Stable Diffusion代码分析 xff08 文本转图像 xff09 论文介绍 xff08 上 xff09 BingLiHanShuang的博客 CSDN博客 二 St
  • 要点初见:Stable Diffusion NovelAI模型优质文字Tag汇总与实践【魔咒汇总】

    目前贴吧 B站上有大量Stable Diffusion的模型资源 TAG TAG生成器分享 xff0c 其中居然有不少试图靠信息差把这些开源资源卖钱的 加上目前网上相关的TAG整理贴极少 xff0c 不少TAG也是以图片的形式存在 xff0
  • UART详解

    UART 通用异步收发传输器 xff08 Universal Asynchronous Receiver Transmitter xff0c 通常称作UART xff09 是一种串行异步收发协议 xff0c 应用十分广泛 UART工作原理是
  • Python订阅自定义ROS topic并读取message

    背景 最近部署了基于ROS的实时稠密场景建图 参考Elastic bridge 现在需要用python获取相机每一时刻的pose 该pose的消息类型定义在FrameState msg 文件中 具体内容如下 uint64 seq uint6
  • 要点初见:双硬盘下的Win10+Ubuntu16.04双系统安装

    按照网上博客的安装教程安装的Win10 43 Ubuntu16 04双系统安装了好几遍都不成功 xff1f 启动Ubuntu左上一直有个光标在闪 xff1f 如果你的电脑也是双硬盘 xff08 装Windows系统的固态硬盘 43 机械硬盘
  • 要点初见:OpenCV3中ORB特征提取算法的实现与分析

    ORB特征提取算法是一种通过检测提取待测图片与模板图片中的灰度特征 xff0c 实现模板图片与待测图片匹配的一种特征提取算法 相比于模板匹配matchTemple xff0c ORB更集中于图像的灰度细节 xff0c 速度也更快 ORB的全
  • 为什么模板函数应该定义在头文件内

    为什么模板函数应该定义在头文件内 tang05505622334的博客 CSDN博客 头文件 模板函数 参考 xff1a https www cnblogs com cnsec p 3789824 htmlgeneral的编译链接过程 xf
  • Cartographer详解

    Cartographer 论文解读 一 Introduction 在建图上应用SLAM并不是一个新的概念 xff0c 这里不再作为本文的重点 本文的贡献在于 xff1a 提出了一种新的基于激光数据的回环检测方法 xff0c 这种方法可以减少
  • C语言实现TCP通信

    C语言通过socket编程实现TCP通信 服务端客户端通信例子 xff1a socket tcp 通信1 xff0c socket tcp通信2 xff0c udp使用讲解 xff0c socket udp通信例子 TCP IP协议 叫做传