socket入门

socket 简介

Socket即套接字,就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口。
在这里插入图片描述
socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。

通信流程

socket是"打开—读/写—关闭"模式的实现,以使用TCP协议通讯的socket为例,其交互流程如下:
在这里插入图片描述

TCP编程步骤:
TCP服务器端一般步骤是:
  1、创建一个socket,用函数socket();
  2、设置socket属性,用函数setsockopt(); 可选
  3、绑定IP地址、端口等信息到socket上,用函数bind();
  4、开启监听,用函数listen();
  5、接收客户端上来的连接,用函数accept();
  6、收发数据,用函数send()和recv(),或者read()和write();
  7、关闭网络连接;
  8、关闭监听;
TCP客户端一般步骤是:
  1、创建一个socket,用函数socket();
  2、设置socket属性,用函数setsockopt();可选
  3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
  4、设置要连接的对方的IP地址和端口等属性;
  5、连接服务器,用函数connect();
  6、收发数据,用函数send()和recv(),或者read()和write();
  7、关闭网络连接;

UDP的编程步骤:
UDP服务器端一般步骤是:
  1、创建一个socket,用函数socket();
  2、设置socket属性,用函数setsockopt();可选
  3、绑定IP地址、端口等信息到socket上,用函数bind();
  4、循环接收数据,用函数recvfrom();
  5、关闭网络连接;
UDP客户端一般步骤是:
  1、创建一个socket,用函数socket();
  2、设置socket属性,用函数setsockopt();可选
  3、绑定IP地址、端口等信息到socket上,用函数bind();可选
  4、设置对方的IP地址和端口等属性;
  5、发送数据,用函数sendto();
  6、关闭网络连接;

linux下socket程序示例

以TCP协议为例,实现的功能是:客户端从服务器读取一个字符串并打印出来。

服务器端代码 server.cpp:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(){//创建套接字int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//将套接字和IP、端口绑定struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充serv_addr.sin_family = AF_INET;  //使用IPv4地址serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址serv_addr.sin_port = htons(1234);  //端口bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));//进入监听状态,等待用户发起请求listen(serv_sock, 20);//接收客户端请求struct sockaddr_in clnt_addr;socklen_t clnt_addr_size = sizeof(clnt_addr);int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);//向客户端发送数据char str[] = "Hello World!";write(clnt_sock, str, sizeof(str));//关闭套接字close(clnt_sock);close(serv_sock);return 0;
}

客户端代码 client.cpp:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main(){//创建套接字int sock = socket(AF_INET, SOCK_STREAM, 0);//向服务器(特定的IP和端口)发起请求struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充serv_addr.sin_family = AF_INET;  //使用IPv4地址serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址serv_addr.sin_port = htons(1234);  //端口connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));//读取服务器传回的数据char buffer[40];read(sock, buffer, sizeof(buffer)-1);printf("Message form server: %s\n", buffer);//关闭套接字close(sock);return 0;
}

先编译 server.cpp 并运行:

[admin@localhost ~]$ g++ server.cpp -o server
[admin@localhost ~]$ ./server

正常情况下,程序运行到 accept() 函数就会被阻塞,等待客户端发起请求。

接下来编译 client.cpp 并运行:

[admin@localhost ~]$ g++ client.cpp -o client
[admin@localhost ~]$ ./client
Message form server: Hello World!
[admin@localhost ~]$

client 运行后,通过 connect() 函数向 server 发起请求,处于监听状态的 server 被激活,执行 accept() 函数,接受客户端的请求,然后执行 write() 函数向 client 传回数据。client 接收到传回的数据后,connect() 就运行结束了,然后使用 read() 将数据读取出来。

需要注意的是:
server 只接受一次 client 请求,当 server 向 client 传回数据后,程序就运行结束了。如果想再次接收到服务器的数据,必须再次运行 server,所以这是一个非常简陋的 socket 程序,不能够一直接受客户端的请求。

源码解析

  1. 先说一下 server.cpp 中的代码。

第11行通过 socket() 函数创建了一个套接字,参数 AF_INET 表示使用 IPv4 地址,SOCK_STREAM 表示使用面向连接的数据传输方式,IPPROTO_TCP 表示使用 TCP 协议。在 Linux 中,socket 也是一种文件,有文件描述符,可以使用 write() / read() 函数进行 I/O 操作。

第19行通过 bind() 函数将套接字 serv_sock 与特定的IP地址和端口绑定,IP地址和端口都保存在 sockaddr_in 结构体中。socket() 函数确定了套接字的各种属性,bind() 函数让套接字与特定的IP地址和端口对应起来,这样客户端才能连接到该套接字。

第22行让套接字处于被动监听状态。所谓被动监听,是指套接字一直处于“睡眠”中,直到客户端发起请求才会被“唤醒”。

第27行的 accept() 函数用来接收客户端的请求。程序一旦执行到 accept() 就会被阻塞(暂停运行),直到客户端发起请求。

第31行的 write() 函数用来向套接字文件中写入数据,也就是向客户端发送数据。

和普通文件一样,socket 在使用完毕后也要用 close() 关闭。

  1. 再说一下 client.cpp 中的代码。client.cpp 中的代码和 server.cpp 中有一些区别。

第19行代码通过 connect() 向服务器发起请求,服务器的IP地址和端口号保存在 sockaddr_in 结构体中。直到服务器传回数据后,connect() 才运行结束。

第23行代码通过 read() 从套接字文件中读取数据。

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

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

相关文章

SPI、I2C、UART 三种串行总线对比介绍

转载自https://blog.csdn.net/oqqHuTu12345678/article/details/65445338 参考博客 https://blog.csdn.net/xiaodingqq/article/details/80342459 https://blog.csdn.net/weiqifa0/article/details/8845281 https://www.zhihu.com/question/22632011 http://www.360doc.cn/…

栈与堆的区别(内存分配与数据结构)

参考自https://blog.csdn.net/K346K346/article/details/80849966/ 堆&#xff08;Heap&#xff09;与栈&#xff08;Stack&#xff09;包含两层含义&#xff1a; 程序内存布局场景下的内存管理方式数据结构中的两种常见的数据结构 1. 程序内存分配中的堆与栈 1.1 栈介绍 …

深入学习卷积神经网络(CNN)的原理知识

转载自https://www.cnblogs.com/wj-1314/p/9754072.html 在深度学习领域中&#xff0c;已经经过验证的成熟算法&#xff0c;目前主要有深度卷积网络&#xff08;DNN&#xff09;和递归网络&#xff08;RNN&#xff09;&#xff0c;在图像识别&#xff0c;视频识别&#xff0c;语…

C/C++中static的用法全局变量与局部变量

转载自C/C中static的用法全局变量与局部变量 1.什么是static? static 是C/C中很常用的修饰符&#xff0c;它被用来控制变量的存储方式和可见性。 1.1static的引入 我们知道在函数内部定义的变量&#xff0c;当程序执行到它的定义处时&#xff0c;编译器为它在栈上分配空间&…

李牛(Linux)脚本

Linux课堂笔记day01 主要总结内容&#xff1a; 一&#xff1a;Linux背景介绍 二&#xff1a;系统操作 三&#xff1a;服务管理 四&#xff1a;shell脚本 五&#xff1a;文本操作 六:常用服务搭建 01&#xff1a;初识linux 收获&#xff1a;可以熟练应对运维和开发 对以后的生…

李牛(Linux)打包

15&#xff1a;打包压缩以及解压缩 接下来我们来介绍打包压缩以及解压缩命令 首先我们要在脑海里想几个问题&#xff1a; 1.打包压缩以及解压缩在字面上理解到底是什么意思&#xff1f; 是不是像我们生活见到的事例那样 比如说&#xff1a;生产酒的厂商一般都是按照规则将12瓶…

jquery实现页面提示,数据正在加载中。(

简单代码&#xff1a; jsp中代码如下&#xff1a;<wbr> <div id"dataLoad" style"display:none"><!--页面载入显示--></wbr><wbr><wbr><table width100% height100% border0 aligncenter valignmiddle></wbr…

李牛(Linux)vi

16&#xff1a;强大的vi 引言&#xff1a;提到vi我们不得不提到vim 这两种编辑器就先当于我们Windows操作系统当中的记事本 不过vi以及vim编辑器熟练掌握之后是不需使用鼠标进行操作的 完全都是由键盘来进行控制 那为什么可以不用鼠标呢 就是因为我们的vi编辑器是基于多模式的…

李牛(Linux)

20&#xff1a;用户和用户组管理 引言&#xff1a; 新思维1&#xff1a;用户&#xff1f;用户是什么&#xff1f;能不能吃&#xff1f;好吃不&#xff01;哈哈 不开玩笑了 我们平常接触的用户就是window系统下的用户 用户名叫啥来着 哦 user 但是对于Windows操作系统来说 好像…

Date类(日期时间类)219

219节课堂笔记 1.概述&#xff1a;表示特定的时间 2.所在的类&#xff1a;java.util.Date(表示时间和日期的类) 类date标识特定的瞬间&#xff0c;精确到毫秒 3.毫秒的换算&#xff1a;1秒1000毫秒 tips&#xff1a;不可以认为是1秒等于60毫秒&#xff0c;与时钟换算是不一样的…

MYSQ产品

前言&#xff1a;MySQL数据库&#xff0c;隶属于MySQLAB公司&#xff0c;总部位于瑞典&#xff0c;后被Oracle收购 MySQLAB公司是由monky及他的两位好朋友创建的&#xff0c;先是被sun公司收购然后被偶尔甲骨文公司收购 MySQL的优点&#xff1a; 1.它的成本是比较低的&#xff…

DateFormat(炸窝)

222&#xff1a;DateFormat方法的使用以及功能&#xff1a; java.text.DateFormat是日期或者时间格式化子类的抽象类&#xff0c;作用&#xff1a;可以帮我们完成日期和文本之间的转换&#xff0c;也就是可以在Date对象与String对象之间进行来回转换 格式化&#xff1a; 按照指…

剑指offer:8-11记录

用两个栈实现一个队列。队列的声明如下&#xff0c;请实现它的两个函数 appendTail 和 deleteHead &#xff0c;分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素&#xff0c;deleteHead 操作返回 -1 ) 示例 1&#xff1a; 输入&#xff1a; ["…

剑指offer:26-30记录

输入两棵二叉树A和B&#xff0c;判断B是不是A的子结构。(约定空树不是任意一个树的子结构) B是A的子结构&#xff0c; 即 A中有出现和B相同的结构和节点值。 例如: 给定的树 A: 3 / \ 4 5 / \ 1 2 给定的树 B&#xff1a; 4 / 1 返回 true&#xff0c;因为…

Calendar类 set方法 get方法 add方法

Calendar类 set方法 get方法 add方法 package asd; import java.util.*; public class zixue { public static void main(String[] args) { demo01();//实验的是get()方法&#xff1b; demo02();//实验的是set()方法&#xff1b; } //---------------------------------------…

剑指offer:33-37记录

输入一个整数数组&#xff0c;判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true&#xff0c;否则返回 false。假设输入的数组的任意两个数字都互不相同。 参考以下这颗二叉搜索树&#xff1a; 5 / \ 2 6 / \ 1 3 示例 1&#xff1a; 输入: [1,6,…

剑指offer:45-48记录

输入一个正整数数组&#xff0c;把数组里所有数字拼接起来排成一个数&#xff0c;打印能拼接出的所有数字中最小的一个。 示例 1: 输入: [10,2] 输出: "102" 示例 2: 输入: [3,30,34,5,9] 输出: "3033459" 提示: 0 < nums.length < 100 说明:…

剑指offer:50-53记录

在字符串 s 中找出第一个只出现一次的字符。如果没有&#xff0c;返回一个单空格。 示例: s "abaccdeff" 返回 "b" s "" 返回 " " 限制&#xff1a; 0 < s 的长度 < 50000 思路&#xff1a;map记录次数&#xff0c;再…

返回地址【数据结构】

小问题&#xff1f; 1.我们是如何根据地址值来找到我们对应的数据的&#xff1f; 详细陈述一下&#xff1a;当我们开辟一个整数类型&#xff0c;取名为a&#xff0c;假设地址空间是从数值为2000进行存储&#xff0c;并且我们假设整形占用4个字节&#xff0c;那么我们在内存中需…

【超级详细的小白教程】Hexo 搭建自己的博客

– 前言 这是一篇有关如何使用 Github Pages 和 Hexo 搭建属于自己独立博客的详尽教程&#xff0c;本人是软件工程专业本科生&#xff0c;目前只学习了C和C编程语言&#xff0c;对网站开发的有关知识几乎为零&#xff0c;这也是我搭建好自己的博客之后写的第一篇博客&#xff…