网络编程 —— TCP 和 UDP 编程详解

目录

网络编程主要函数介绍

1. socket 函数

2. bind 函数

3. listen 函数

4. accept 函数

5. connect 函数

6. send 函数

7. recv 函数

8. recvfrom 函数

9. sendto 函数

TCP 和 UDP 原理上的区别

TCP 编程

服务端代码:

客户端代码:

UDP 编程

服务端代码:

客户端代码:


网络编程主要函数介绍

1. socket 函数

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

此函数用于创建一个套接字

domain 是网络程序所在的主机采用的通讯协族(AF_UNIX 和 AF_INET 等)。

  • AF_UNIX 只能够用于单一的 Unix 系统进程间通信,而 AF_INET 是针 对 Internet 的,因而可以允许远程通信使用。

type 是网络程序所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM 等)。

  • SOCK_STREAM 表明用的是 TCP 协议,这样会提供按顺序的,可靠,双向,面向连接的比特流。
  • SOCK_DGRAM 表明用的是 UDP 协议,这样只会提不可靠,无连接的通信。

关于 protocol,由于指定了 type,所以这个地方一般只要用 0 来代替就可以了。

此函数执行成功时返回文件描述符,失败时返回-1,看 errno 可知道出错的详细情况

2. bind 函数

int bind(int sockfd, struct sockaddr *my_addr, int addrlen);

从函数用于将地址绑定到一个套接字。

sockfd 是由 socket 函数调用返回的文件描述符。

my_addr 是一个指向 sockaddr 的指针。

addrlen 是 sockaddr 结构的长度。

sockaddr 的定义:

struct sockaddr{

unisgned short as_family;

char sa_data[14];

};

不 过 由 于 系 统 的 兼 容 性 , 我 们 一 般 使 用 另 外 一 个 结 构 (struct sockaddr_in) 来代替。 sockaddr_in 的定义:

struct sockaddr_in{

unsigned short  sin_family;

unsigned short  sin_port;

struct in_addr    sin_addr; // // 结构体套结构体 sin_addr.s_addr

unsigned char   sin_zero[8];

}

如果使用 Internet 所以 sin_family 一般为 AF_INET。

sin_addr 设置为 INADDR_ANY 表示可以和任何的主机通信。

sin_port 是要监听的端口号。

bind 将本地的端口同 socket 返回的文件描述符捆绑在一起.

成功则返回 0, 失败则情况和 socket 一样。

3. listen 函数

int listen(int sockfd,int backlog);

此函数宣告服务器可以接受连接请求。

sockfdbind 后的文件描述符。

backlog 设置请求排队的最大长度。当有多个客户端程序和服务端相连时, 使用这个表示可以介绍的排队长度。

listen 函数将 bind 的文件描述符变为监听套接字,返回的情况和 bind 一 样。

4. accept 函数

int accept(int sockfd, struct sockaddr *addr,int *addrlen);

服务器使用此函数获得连接请求,并且建立连接。

addr,addrlen 是用来给客户端的程序填写的,服务器端只要传递指针就可以了, bind,listen 和 accept 是服务器端用的函数。

accept 调用时,服务器端的程序会一直阻塞到有一个客户程序发出了连接。

accept 成功时返回最后的服务器端的文件描述符,这个时候服务器端可以向该描述符写信息了,失败时返回-1 。

5. connect 函数

int connect(int sockfd, struct sockaddr * serv_addr,int addrlen);

可以用 connect 建立一个连接,在 connect 中所指定的地址是想与之通信的服务器的地址。

sockfd 是 socket 函数返回的文件描述符。

serv_addr 储存了服务器端的连接信息,其中 sin_add 是服务端的地址。

addrlen 是 serv_addr 的长度

connect 函数是客户端用来同服务端连接的.成功时返回 0,sockfd 是同服 务端通讯的文件描述符,失败时返回-1。

6. send 函数

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

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

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

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

flags 一般置 0。

客户或者服务器应用程序都用 send 函数来向 TCP 连接的另一端发送数据

7. recv 函数

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

sockfd 指定接收端套接字描述符;

buf 指明一个缓冲区,该缓冲区用来存放 recv 函数接收到的数据;

len 指明 buf 的长度;

flags 一般置 0。

客户或者服务器应用程序都用 recv 函数从 TCP 连接的另一端接收数据。

8. recvfrom 函数

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr,  socklen_t *addrlen);

recvfrom 通常用于无连接套接字,因为此函数可以获得发送者的地址。

src_addr 是一个 struct sockaddr 类型的变量,该变量保存源机的 IP 地址及端口号。

addrlen 常置为 sizeof (struct sockaddr)。

9. sendto 函数

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,

                                 const struct sockaddr *dest_addr, socklen_t addrlen);

sendto 和 send 相似,区别在于 sendto 允许在无连接的套接字上指定一个目标地址。

dest_addr 表示目地机的 IP 地址和端口号信息,

addrlen 常常被赋值为 sizeof (struct sockaddr)

sendto 函数也返回实际发送的数据字节长度或在出现发送错误时返回-1。

TCP 和 UDP 原理上的区别

TCP 向它的应用程序提供了面向连接的服务。这种服务有 2 个特点:可靠传输、流量控制(即发送方/接收方速率匹配)。它包括了应用层报文划分为短报文, 并提供拥塞控制机制。

UDP 协议向它的应用程序提供无连接服务。它没有可靠性,没有流量控制, 也没有拥塞控制。

TCP 编程

服务端运用到的函数:

  • 1. socket
  • 2. bind 
  • 3. listen
  • 4. accept
  • 5. recv

服务端代码:

#include <sys/types.h>         
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>/* socket* bind* listen* accept* send/recv*/#define SERVER_PORT 8888
#define BACKLOG     10int main(int argc, char **argv)
{int iSocketServer;int iSocketClient;struct sockaddr_in tSocketServerAddr;struct sockaddr_in tSocketClientAddr;int iRet;int iAddrLen;int iRecvLen;unsigned char ucRecvBuf[1000];int iClientNum = -1;signal(SIGCHLD,SIG_IGN); // 信号量,避免出现僵尸进程// 创建服务端套接字iSocketServer = socket(AF_INET, SOCK_STREAM, 0);if (-1 == iSocketServer){printf("socket error!\n");return -1;}// 设置服务器地址信息tSocketServerAddr.sin_family      = AF_INET;tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;memset(tSocketServerAddr.sin_zero, 0, 8);// 绑定套接字到指定地址和端口iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));if (-1 == iRet){printf("bind error!\n");return -1;}// 监听连接请求	iRet = listen(iSocketServer, BACKLOG);if (-1 == iRet){printf("listen error!\n");return -1;}while (1){iAddrLen = sizeof(struct sockaddr);iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen); // 接受客户端连接if (-1 != iSocketClient){iClientNum++;printf("Get connect from client %d : %s\n",  iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));if (!fork()){/* 子进程的源码 */while (1){/* 接收客户端发来的数据并显示出来 */iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);if (iRecvLen <= 0){close(iSocketClient);return -1;}else{ucRecvBuf[iRecvLen] = '\0';printf("Get Msg From Client %d: %s\n", iClientNum, ucRecvBuf);}}				}}}close(iSocketServer);return 0;
}

客户端运用到的函数:

  • 1. socket
  • 2. connect
  • 3. send

客户端代码:

#include <sys/types.h>        
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>/* socket* connect* send/recv*/#define SERVER_PORT 8888int main(int argc, char **argv)
{int iSocketClient;struct sockaddr_in tSocketServerAddr;int iRet;unsigned char ucSendBuf[1000];int iSendLen;if (argc != 2){printf("Usage:\n");printf("%s <server_ip>\n", argv[0]);return -1;}// 创建客户端套接字iSocketClient = socket(AF_INET, SOCK_STREAM, 0);// 设置服务器地址信息tSocketServerAddr.sin_family      = AF_INET;tSocketServerAddr.sin_port        = htons(SERVER_PORT);  // host to net 端口号if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)) //  ASCLL to net 把argv[1]存到地址中去{printf("invalid server_ip\n");return -1;}memset(tSocketServerAddr.sin_zero, 0, 8); // 清0iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));	if (-1 == iRet){printf("connect error!\n");return -1;}while (1){if (fgets(ucSendBuf, 999, stdin)) // 从输入流stdin即输入缓冲区中读取999个字符到sendbuf中{iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);if (iSendLen <= 0){close(iSocketClient);return -1;}}}return 0;
}

编译执行结果:

UDP 编程

服务端运用到的函数:

  • 1. socket
  • 2. bind 
  • 3. listen
  • 4. accept
  • 5. recv

服务端代码:

#include <sys/types.h>         
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>/* socket* bind* sendto/recvfrom*/#define SERVER_PORT 8888int main(int argc, char **argv)
{int iSocketServer;int iSocketClient;struct sockaddr_in tSocketServerAddr;struct sockaddr_in tSocketClientAddr;int iRet;int iAddrLen;int iRecvLen;unsigned char ucRecvBuf[1000];int iClientNum = -1;iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == iSocketServer){printf("socket error!\n");return -1;}tSocketServerAddr.sin_family      = AF_INET;tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;memset(tSocketServerAddr.sin_zero, 0, 8);iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));if (-1 == iRet){printf("bind error!\n");return -1;}while (1){iAddrLen = sizeof(struct sockaddr);iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);if (iRecvLen > 0){ucRecvBuf[iRecvLen] = '\0';printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);}}close(iSocketServer);return 0;
}

客户端运用到的函数:

  • 1. socket
  • 2. connect
  • 3. send

客户端代码:

#include <sys/types.h>         
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>/* socket* connect* send/recv*/#define SERVER_PORT 8888int main(int argc, char **argv)
{int iSocketClient;struct sockaddr_in tSocketServerAddr;int iRet;unsigned char ucSendBuf[1000];int iSendLen;int iAddrLen;if (argc != 2){printf("Usage:\n");printf("%s <server_ip>\n", argv[0]);return -1;}iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);tSocketServerAddr.sin_family      = AF_INET;tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)){printf("invalid server_ip\n");return -1;}memset(tSocketServerAddr.sin_zero, 0, 8);#endifwhile (1){if (fgets(ucSendBuf, 999, stdin)){iAddrLen = sizeof(struct sockaddr);iSendLen = sendto(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0,(const struct sockaddr *)&tSocketServerAddr, iAddrLen);if (iSendLen <= 0){close(iSocketClient);return -1;}}}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/174988.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

http接口测试—自动化测试框架设计

一、测试需求描述 对服务后台一系列的http接口功能测试。 输入&#xff1a;根据接口描述构造不同的参数输入值&#xff08;Json格式&#xff09; 输出&#xff1a;字符串&#xff08;传入的方式传入的字符串&#xff09; http://localhost:8090/lctest/TestServer 二、程序设计…

浅谈:Flutter现状、与为什么选择Flutter——其实大家都在用只是你不知道罢了

浅谈&#xff1a;谁将会动那些抵制学习还装懂的人的蛋糕 开发环境现状与为什么选择Flutter 我本从不屑于写这种技术外的技术文章&#xff0c;但是今天刷某应用优点上头&#xff0c;想发唯一一篇。这篇文章可能会得罪一些就喜欢地址学新架构的&#xff0c;以及还不了解就开始起哄…

8、数据结构-字符串、编码集

编码表 中文编码表 ​ 数字到中文单一字符的映射&#xff0c;汉字只能使用多字节的2字节&#xff0c;总有65535种状态。常见的中文编码有GB2312 、GBK 、GB18030 、BIG 5。 ​ 所有编码表都兼容单字节的ASCII表。 UNICODE ​ 多字节&#xff0c;一张编码表解决全球多数字符…

【C++】join ()和detach ()函数详解和示例

简单的来说&#xff0c;join ()方法建立的线程具有阻碍作用&#xff0c;该线程不结束&#xff0c;另一些函数就无法运行。detach ()方法建立的线程&#xff0c;可以和另一些函数同时进行。下面以示例进行详细说明&#xff0c;以帮助大家理解和使用。 目录 join ()detach () jo…

计算机毕业设计 基于SpringBoot的销售项目流程化管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

学开发语言 求职互联网行业的未来发展

我喜欢回答各种各样的问题&#xff0c;自然也喜欢记录下自己的一些观点和看法。希望给朋友们多一点参考&#xff0c;也欢迎交流探讨。 提问&#xff1a; 自考本科&#xff0c;学的开发语言&#xff0c;问互联网行业求职和发展&#xff01; 作为一个资深码农&#xff0c;对这样…

神经网络中的量化与蒸馏

本文将深入研究深度学习中精简模型的技术&#xff1a;量化和蒸馏 深度学习模型&#xff0c;特别是那些具有大量参数的模型&#xff0c;在资源受限环境中的部署几乎是不可能的。所以就出现了两种流行的技术&#xff0c;量化和蒸馏&#xff0c;它们都是可以使模型更加轻量级&…

LeetCode(13)除自身以外数组的乘积【数组/字符串】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 238. 除自身以外数组的乘积 1.题目 给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素…

新能源充电桩物联网应用之工业4G路由器

新能源充电桩是智慧城市建设中不可缺少且可持续发展的重要设施&#xff0c;而工业4G路由器物联网应用为其提供了更加高效、智能、实时的管理方式。充电桩通过工业4G路由器可以与充电运营商的管理中心建立稳定的连接&#xff0c;实现双向数据传输&#xff0c;为用户提供优质的充…

人工智能基础_机器学习030_ElasticNet弹性网络_弹性回归的使用---人工智能工作笔记0070

然后我们再来看elastic-net弹性网络,之所以叫弹性是因为,他融合了L1和L2正则,可以看到 他的公式 公式中有L1正则和L2正则两个都在这个公式中 可以看到弹性网络,在很多特征互相联系的时候,非常有用,比如, 相关性,如果数学好,那么物理也好,如果语文好,那么英语也好 这种联系 正…

thinkphp6(TP6)访问控制器报404(Nginx)

起因&#xff1a; 安装thinphp6后&#xff0c;发现无法访问控制器&#xff0c;直接通过URL访问&#xff0c;就报错404。 错误原因&#xff1a; Nginx不支持URL的 PathInfo。 解决方法&#xff1a; 配置伪静态。 伪静态代码&#xff1a; location / {if (!-e $request_filen…

5个用于地理空间数据分析的Python包

大家好&#xff0c;地理空间数据分析在城市规划、环境研究、农业和交通等行业中至关重要。不断增长的需求导致Python包在各种地理数据分析要求上的使用增加&#xff0c;例如分析气候模式、研究城市发展或跟踪疾病传播等&#xff0c;评估和选择具有快速处理、修改和可视化能力的…