基于TCP的Socket网络编程

2023-11-14

前言:
Socket通信是基于TCP/IP协议的通信。在工作和做项目中应用非常广,下面来介绍下Socket网络编程!

Socket的介绍

首先,在Socket网络编程中我们要了解两个重要的东西,ip和端口号,一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等。这些服务完全可以通过1个ip地址来实现。主机是怎样区分不同的网络服务的?显然不能只靠ip地址,因为ip地址与网络服务的关系是一对多的关系。
实际上是通过“ip地址+端口号”来区分不同的服务的。一般端口号在5000~10000。

1.字节序

字节序:指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
Little endian(小端字节序):将低序字节存储在起始地址。
Big endian(大端字节序):将高序字节存储在起始地址。

举个例子:int a = 0x12345678;
0x78属于低地址,而0x12属于高地址
如果是大端模式,那输出方式是0x12 0x34 0x56 0x78,如果是小端模式,那么就是0x78 0x56 0x34 0x12

这个很容易理解,人类读写数据的习惯是大端字节序,而小端字节序是反着人类来的,而我们网络字节序传输是大端模式,因此要转为大端模式。

2.字节序转换api:

 #include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue);    //返回网络字节序的值uint32_t
 htonl(uint32_t host32bitvalue);    //返回网络字节序的值uint16_t ntohs(uint16_t
 net16bitvalue);     //返回主机字节序的值uint32_t ntohl(uint32_t net32bitvalue);
 //返回主机字节序的值

 h代表host,n代表net,s代表short(两个字节),l代表long4个字节),通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取

Socket的开发步骤

Socket服务器和客户端的开发步骤:
在这里插入图片描述

Linux提供的API简析

1.socket(创建套接字)

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

在这里插入图片描述

2.bind()函数

 #include <sys/types.h>          /* See NOTES */
 #include <sys/socket.h>

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

功能:用于绑定ip地址跟端口号到socketfd。
 参数说明:
 sockfd--是一个文件描述符
 addr:是一个指向包含有本地IP及端口号等信息等信息的sockaddr类型的指针,指向要绑定给socket的协议地址结构,这个地址结构根据地址创建socket时的地址协议族的不同而不同。

在这里插入图片描述

struct sockaddr_in结构体:

 struct sockaddr_in
 {  
	 sa_family_t sin_family; //指定AF_***,表示使用什么协议族的ip格式  __be16       sin_port;   //设置端口号  struct
	 in_addr  sin_addr;   //设置ip  
	 unsigned char  __pad[__SOCK_SIZE__ -sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)];
 }; 

struct in_addr
{  
	__be32 s_addr;  //32位的无符号整型数据 
}; 

bind函数绑定实例:

此结构体因为成员中设置ip和端口的变量时分开的,所以设置方便,但是bind函数要求的是struct sockaddr类型的结构体变量,所以使用struct sockaddr_in设置以后要将其强制转化为struct sockaddr类型,然后传值给bind函数。

 struct sockaddr_in addr;  //首先定义结构体变量
 addr.sin_family = AF_INET;  //指定协议族为IPV4版本的TCP/IP协议族 addr.sin_port =
 htons(5006);  //指定端口号 addr.sin_addr.s_addr =
 inet_addr("192.168.1.10"); //指定IP ret = bind(sockfd,(struct
 sockaddr*)&addr,sizeof(sddr)); //进行套接字文件/ip/端口的绑定

htons函数

功能:将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian);

 #include <arpa/inet.h>
uint16_t htons(uint16_t hostshort);
addr.sin_port = htons(5006);

inet_addr函数

功能:将一个字符串格式的ip地址转换成一个uint32_t数字格式。

 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 in_addr_t inet_addr(const char *cp);
 eg:
 addr.sin_addr.s_addr = inet_addr("192.168.1.10");

地址转换API

  int inet_aton(const char* straddr,struct in_addr *addrp);
   把字符串形式的“192.168.1.123”转为网络能识别的格式
 
 
 char* inet_ntoa(struct in_addr inaddr);  把网络格式的ip地址转为字符串形式

3.listen()函数

 #include <sys/types.h>
 #include <sys/socket.h>
 
 int listen(int sockfd, int backlog);
功能:监听设置函数
 参数说明:
 sockfd:文件描述符
 backlog:指定在请求队列中允许的最大请求数

4.accept()函数

 #include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
 int accept(int sockfd, struct sockaddr *addr, socklen_t*addrlen);
 
 功能:accept函数由TCP服务器调用,用于从已完成连接队列队头返回下一个已完成连接,如果已完成连接队列为空,那么进程被投入睡眠。
 
 参数说明:
sockfd:文件描述符
addr:用来返回已连接的对端(客户端)的协议地址
addrled:客户端地址长度
返回值:accept函数返回值成功时返回非负值,失败时返回-1

5.1. 数据收发(recv 、send)

函数原型:ssize_t send(int sockfd, const void *buf, size_t len, int flags);
 
功能:向套接字中发送数据
参数:
 sockfd:向套接字中发送数据
 buf:要发送的数据的首地址
 len:要发送的数据的字节
  int flags:设置为MSG_DONTWAITMSG 时 表示非阻塞 设置为0时 功能和write一样
返回值:成功返回实际发送的字节数,失败返回 -1 


 函数原型:ssize_t recv(int sockfd, const void *buf, size_t len, int flags);

 功能:向套接字中发送数据 
 参数: 	  
sockfd:在哪个套接字接
buf:存放要接收的数据的首地址
len:要接收的数据的字节
int flags:设置为MSG_DONTWAITMSG 时 表示非阻塞设置为0时 功能和read一样        
返回值:成功返回实际发送的字节数,失败返回 -1

5.2. 数据收发(read 、write)

 #include <unistd.h>
 ssize_t read(int fd, void * buf, size_t nbytes);
 #include <unistd.h>
ssize_t write(int fd, const	void *buf, size_t nbytes);

6.客户端的connect函数

#include <sys/types.h> /* See NOTES */
 #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 
 
 参数说明:
 sockfd: socket文件描述符
 addr: 传入参数,指定服务器端地址信息,含IP地址和端口号 
 addrlen: 传入参数,传入sizeof(addr)大小 
 返回值:成功返回0,失败返回-1,设置errno

7. 一个客户端与服务器连接的demo

服务器:

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <stdlib.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char **argv)
{
        int s_fd;
        int c_fd;
        int ret;
        int n_read;
        char readBuf[128];
        char msg[128]={0};
        // char *writeBuf="I get your message!";
        int mark=0;
        //1.socket
        s_fd = socket(AF_INET,SOCK_STREAM ,0);
        if(s_fd == -1){

                perror("socket");
                exit(-1);
        }

        if(argc!=3){
                printf("pamrm error\n");
                exit(-1);
        }

        struct sockaddr_in a_addr;
        struct sockaddr_in c_addr;
        memset(&a_addr,0,sizeof(struct sockaddr_in));
        memset(&c_addr,0,sizeof(struct sockaddr_in));

        a_addr.sin_family=AF_INET;
        a_addr.sin_port=htons(atoi(argv[2]));
        a_addr.sin_addr.s_addr=inet_addr(argv[1]);
        //  inet_ntoa("172.20.10.3",&addr.sin_addr.s_addr);
        //2.bind
        ret = bind(s_fd,(struct sockaddr*)&a_addr,sizeof(struct sockaddr_in));
        if(ret==-1){
                perror("bind");
                exit(-1);
 }
        //3.listen
        int len=sizeof(struct sockaddr_in);
        listen(s_fd,10);

        while(1){
                //4.accept
                c_fd = accept(s_fd,(struct sockaddr*)&c_addr,&len);
                mark++;
                printf("get connect: %s\n",inet_ntoa(c_addr.sin_addr));
                if(fork()==0){
                        if(fork()==0){
                                while(1){
                                        sprintf(msg,"Welcome to No%d client\n",mark);
                                        write(c_fd,msg,strlen(msg));
                                        sleep(3);
                                }
                        }
                        //5.read
                        while(1){
                                memset(readBuf,0,sizeof(readBuf));
                                n_read=read(c_fd,readBuf,128);
                                if(n_read==-1){
                                        perror("read");
                                }else{
                                        printf("get:%s\n",readBuf);
                                }
                        }
                              break;
                }
                //6.write
        }
        return 0;
}

客户端:

include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <stdlib.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char **argv)
{
        int c_fd;
        int ret;
        int n_read;
        char msg[128]={0};
        char readBuf[128]={0};

        c_fd=socket(AF_INET,SOCK_STREAM,0);
        if(c_fd==-1){
                perror("socket");
                exit(-1);
        }

        struct sockaddr_in addr;
        addr.sin_family=AF_INET;
        addr.sin_port=htons(atoi(argv[2]));
        addr.sin_addr.s_addr=inet_addr(argv[1]);

        ret=connect(c_fd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));
        if(ret==-1){
                perror("connect");
                exit(-1);
        }

        while(1){

                if(fork()==0){
                        while(1){
                                memset(msg,0,sizeof(msg));
                                printf("input ");
                                gets(msg);
                                write(c_fd,msg,sizeof(msg));
                        }
                }
 while(1){

                        memset(readBuf,0,sizeof(readBuf));
                        n_read=read(c_fd,readBuf,sizeof(readBuf));
                        if(n_read==-1){

                                perror("read");
                        }else{
                                printf("get:%s\n",readBuf);
                        }

                }





        }





        return 0;
}



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于TCP的Socket网络编程 的相关文章

  • 强制卸载 NFS 安装目录 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案
  • 跟踪 Linux 程序中活跃使用的内存

    我想跟踪各种程序在特定状态下接触了多少内存 例如 假设我有一个图形程序 最小化时 它可能会使用更少的内存 因为它不会重新绘制窗口 这需要读取图像和字体并执行大量库函数 这些对象仍然可以在内存中访问 但实际上并没有被使用 类似的工具top它们
  • 通过特定分隔符删除字符串

    我的文件中有几列 其中第二列有 分隔符 我想删除第二列中的第一个 第三个和第四个字符串 并将第二个字符串留在该列中 但我有正常的分隔符空间 所以我不知道 input 22 16050075 A G 16050075 A G 22 16050
  • 如何禁用 GNOME 桌面屏幕锁定? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何阻止 GNOME 桌面在几分钟空闲时间后锁定屏幕 我已经尝试过官方手册了在红帽 https access redhat com doc
  • 如何根据 HTTP 请求使用 Python 和 Flask 执行 shell 命令并流输出?

    下列的这个帖子 https stackoverflow com questions 15092961 how to continuously display python output in a webpage 我能够tail f网页的日志
  • 大多数 Linux 系统头文件与 C++ 兼容吗?

    大多数 Linux 系统头文件 API C 兼容吗 今天我试图做这样的事情 include
  • 无法从 jenkins 作为后台进程运行 nohup 命令

    更新 根据下面的讨论 我编辑了我的答案以获得更准确的描述 我正在尝试从詹金斯运行 nohup 命令 完整的命令是 nohup java jar home jar server process 0 35 jar prod gt gt var
  • 从 Python 调用 PARI/GP

    我想打电话PARI GP http pari math u bordeaux fr dochtml gpman html仅从Python计算函数nextprime n 对于不同的n是我定义的 不幸的是我无法得到帕里蟒蛇 http code
  • 使用 sed 更新 xml 属性(Windows + cygwin 和 Linux)?

    我需要使用 sed 命令对 xml 文件进行更新 但我在这方面遇到了麻烦 它需要在 Windows 使用 cygwin 和 Linux 上运行 XML 具有以下元素
  • fopen 不返回

    我在 C 程序中使用 fopen 以只读模式 r 打开文件 但就我而言 我观察到 fopen 调用没有返回 它不返回 NULL 或有效指针 执行在 fopen 调用时被阻止 文件补丁绝对正确 我已经验证过 并且不存在与权限相关的问题 任何人
  • 如何在数组中存储包含双引号的命令参数?

    我有一个 Bash 脚本 它生成 存储和修改数组中的值 这些值稍后用作命令的参数 对于 MCVE 我想到了任意命令bash c echo 0 0 echo 1 1 这解释了我的问题 我将用两个参数调用我的命令 option1 without
  • Pyaudio 安装错误 - “命令‘gcc’失败,退出状态 1”

    我正在运行 Ubuntu 11 04 Python 2 7 1 并想安装 Pyaudio 于是我跑了 sudo easy install pyaudio 在终端中 进程退出并显示以下错误消息 Searching for pyaudio Re
  • CentOS:无法安装 Chromium 浏览器

    我正在尝试在 centOS 6 i 中安装 chromium 以 root 用户身份运行以下命令 cd etc yum repos d wget http repos fedorapeople org repos spot chromium
  • ubuntu:升级软件(cmake)-版本消歧(本地编译)[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我的机器上安装了 cmake 2 8 0 来自 ubuntu 软件包 二进制文件放置在 usr bin cmake 中 我需要将 cmake 版本至少
  • PHP 无法打开流:是一个目录

    非常简单的 PHP 脚本 我在我亲自设置的 Ubuntu Web 服务器上的 EE 模板中运行 我知道这与权限有关 并且我已经将我尝试写入的目录的所有者更改为 Apache 用户 我得到的错误是 遇到 PHP 错误 严重性 警告 消息 fi
  • SSE:跨页边界的未对齐加载和存储

    我在页面边界旁边执行未对齐加载或存储之前读过某处 例如使用 mm loadu si128 mm storeu si128内在函数 代码应首先检查整个向量 在本例中为 16 个字节 是否属于同一页 如果不属于同一页 则切换到非向量指令 我知道
  • 在我的 index.php 中加载 CSS 和 JS 等资源时出现错误 403

    我使用的是 Linux Elementary OS 并在 opt 中安装了 lampp My CSS and JS won t load When I inspect my page through browser The console
  • 查找哪些页面不再与写入时复制共享

    假设我在 Linux 中有一个进程 我从中fork 另一个相同的过程 后forking 因为原始进程将开始写入内存 Linux写时复制机制将为进程提供与分叉进程使用的不同的唯一物理内存页 在执行的某个时刻 我如何知道原始进程的哪些页面已被写
  • 如何确保应用程序在 Linux 上持续运行

    我试图确保脚本在开发服务器上保持运行 它会整理统计数据并提供网络服务 因此它应该会持续存在 但一天中有几次 它会因未知原因而消失 当我们注意到时 我们只需再次启动它 但这很麻烦 并且某些用户没有权限 或专有技术 来启动它 作为一名程序员 我
  • 如何使用 GOPATH 的 Samba 服务器位置?

    我正在尝试将 GOPATH 设置为共享网络文件夹 当我进入 export GOPATH smb path to shared folder I get go GOPATH entry is relative must be absolute

随机推荐

  • sonarqube主要功能概览

    sonarqube质量标准 sonarqube通过可靠性 安全性 安全复审 可维护性 覆盖率 重复度等方面来评价代码质量 分别使用bugs 漏洞等指标 如图 有项目状态为正常 有项目状态为错误 点进项目可以看具体 可以对问题进行分配 处理
  • 【剑指Offer】(字符串)左旋转字符串(翻转操作)

    题目链接 https www nowcoder com practice 12d959b108cb42b1ab72cef4d36af5ec tpId 13 tqId 11196 tPage 1 rp 1 ru ta coding inter
  • python游戏编程培训

    准备好了吗 我们即将开始激动人心的游戏编程之旅 或许你之前学习过一点编程 但若是你从没接触过游戏编程 那么你仍然会对游戏程序的运行感到不解 游戏程序不像计算一个公式或谜题 得到答案之后程序就结束了 游戏程序一直是处于运行中的 只要你不主动退
  • 递归行为时间复杂度计算:master公式

    master公式 T N a T N b O N d 公式解释 N是初始问题的负责度 a是次数的意思 也就是调用相同规模的递归次数 b是递归的划分 也就是将原问题划分成相同规模的b份 O N d d是除去递归代码外的其他运算的时间复杂度 例
  • python爬虫系列6--模拟登陆相关

    方式原理 爬虫爬取数据时 有些数据并不能让游客访问到 这时候就需要进行登录 再爬取数据 登录后再爬取的手段很多 但核心都是通过cookie的方式来记录身份信息 因此模拟登录的核心在于对cookie的使用 参考链接 https www cnb
  • Android Kotlin的学习

    1 kotlin简介 Kotlin是一种在Java虚拟机上运行的静态类型编程语言 它也可以被编译成为JavaScript源代码 它主要是由俄罗斯圣彼得堡的JetBrains开发团队所发展出来的编程语言 其名称来自于圣彼得堡附近的科特林岛 3
  • 【CLIP速读篇】Contrastive Language-Image Pretraining

    CLIP速读篇 Contrastive Language Image Pretraining 0 前言 Abstract 1 Introduction and Motivating Work 2 Approach 2 1 Natural L
  • 从元宇宙角度看社交出海产品新体验

    提到社交产品 不可避免的会涉及元宇宙方向 那么元宇宙距离落地还有哪些问题 解决这些问题是否会是新的产品机会 社交作为元宇宙赛道的细分领域之一 如何在未来几年向元宇宙产品发展 打造产品新体验 实现用户增长 本文整理自拍乐云行业解决方案专家奚振
  • 《普林斯顿微积分》读书笔记

    写在前面 并不完整 只有零散的记忆 二 三刷的时候再补充吧 一些初等函数的导数 例如 x n n x n 1 sin x cos x 积分等于反导数 其他 待补充
  • games101 作业3

    遇到的问题 1 项目才打开时无法运行 解决方法 切换成c 17 解决方法引用 Games101 作业3 环境问题 知乎 注 知乎里面的关于越界限制的控制不适用 虽然可以解决部分作业的问题 但是在bump里面依然会出现越界错误 应该用以下大佬
  • VS2022+OpenCV4.6.0+MFC环境配置

    一 环境安装 OpenCV Releases OpenCVhttps opencv org releases VS2022 Visual Studio 面向软件开发人员和 Teams 的 IDE 和代码编辑器Visual Studio 开发
  • 【selenium3+JAVA】界面自动化测试教程(六)——元素查找和操作

    一 前言 元素查找为selenium的基础操作 基本上大部分操作都是基于元素的 故此部分为必须掌握内容 方法包括通过名称 id tagName xpath等方法 下面会详细介绍这些方法 二 元素查找 下面一一介绍这些方法 无论哪种查找方式
  • IC验证工程师工作一周年的体会

    转眼之间自己已经工作一周年了 作为一名验证工程师 这一年里面感觉自己虽然有了一定的成长 但是成长的还是比较缓慢的 接下来从个人的角度说说我现在对从IC验证的一些体会 一 要养成良好的工作习惯 1 自己在工作中发现很多时候都是可以偷懒的 有时
  • Docker网络模式

    目录 Docker 网络 Docker 网络图解 Docker 四种网络模式 Host 模式 Container模式 None模式 Bridge模式 Docker 网络自定义 查看网络列表 自定义网络固定IP 暴露端口 在宿主机环境执行容器
  • 软件测试新手入门小知识点,一定要牢记

    引言 最近有很多朋友来问我做测试难不难 需要注意哪些 接下来就给大家讲讲软件测试新手入门需要了解的小知识点 这些软件测试常识你必须牢记 一 软件测试 软件测试存在的意义 1 发现程序中的错误而执行程序的过程 2 检验产品是否符合用户需求 3
  • Prometheus 监控mysql

    目录 下载安装mysqld exporter 在mysql中创建监控用户并赋权 启动mysqld exporter 添加到系统服务 浏览器访问服务器9104端口 在prometheus定义job来监控mysqld 运行prometheus并
  • Linux系统查看硬盘空间的常用命令!

    在Linux系统中 查看硬盘空间使用情况可以使用命令来完成 其中比较常见的命令有 df和du 那么它们具体如何使用呢 本文为大家详细介绍一下 快来学习吧 查看磁盘空间 df df命令以磁盘分区为单位查看文件系统中磁盘空间的使用情况 选项 h
  • VS2019 + Qt5.12 配置完成后,无法打开 Qt 源文件解决方案(非常实用)

    注 本文主要是解决 VS 无法打开 Qt 源文件问题 关于 VS Qt 配置问题 网上一搜一大堆 各个版本都有 这里就不做详细阐述了 最近自己在使用 VS2019 建立 Qt 工程的时候 遇到了无法打开 Qt 源文件问题 在网上阅读了大量的
  • 每天一个设计模式之 -- 组合模式

    组合模式 组合模式 Composite Pattern 又叫部分整体模式 是用于把一组相似的对象当作一个单一的对象 组合模式依据树形结构来组合对象 用来表示部分以及整体层次 这种类型的设计模式属于结构型模式 它创建了对象组的树形结构 这种模
  • 基于TCP的Socket网络编程

    前言 Socket通信是基于TCP IP协议的通信 在工作和做项目中应用非常广 下面来介绍下Socket网络编程 Socket的介绍 首先 在Socket网络编程中我们要了解两个重要的东西 ip和端口号 一台拥有IP地址的主机可以提供许多服