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,一经查实,立即删除!

相关文章

leetcode614. 二级关注者(SQL)

在 facebook 中&#xff0c;表 follow 会有 2 个字段&#xff1a; followee, follower &#xff0c;分别表示被关注者和关注者。 请写一个 sql 查询语句&#xff0c;对每一个关注者&#xff0c;查询他的关注者数目。 比方说&#xff1a; ------------------------- | follow…

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/…

leetcode1045. 买下所有产品的客户(SQL)

Customer 表&#xff1a; ---------------------- | Column Name | Type | ---------------------- | customer_id | int | | product_key | int | ---------------------- product_key 是 Product 表的外键。 Product 表&#xff1a; ---------------------- | C…

Oracle利用序列实现自动增长列

在SQL Server以及MySql中都有相应的自动增长列类型,而Oracle中则没有此类型,那如果要实现自动增长列需要怎么办呢. 我们可以利用序列来实现.插入数据时候,可以像sql以及mysql一样,不用显示指定需要自动增长的列的值. 代码实现如下: CREATE TABLE SYS_ROLES ( ID integer NOT NU…

C++ new和malloc的区别

这里先对new和delete简单进行一下总结&#xff0c;然后再细说new和malloc的区别。 一、new和delete C语言提供了malloc和free两个系统函数&#xff0c;完成对堆内存的申请和释放。而C则提供了两个关键字new和delete&#xff1b; 1.1 规则 new/delete是关键字&#xff0c;效率…

leetcode620. 有趣的电影(SQL)

某城市开了一家新的电影院&#xff0c;吸引了很多人过来看电影。该电影院特别注意用户体验&#xff0c;专门有个 LED显示板做电影推荐&#xff0c;上面公布着影评和相关电影描述。 作为该电影院的信息部主管&#xff0c;您需要编写一个 SQL查询&#xff0c;找出所有影片描述为…

leetcode1050. 合作过至少三次的演员和导演(SQL)

ActorDirector 表&#xff1a; ---------------------- | Column Name | Type | ---------------------- | actor_id | int | | director_id | int | | timestamp | int | ---------------------- timestamp 是这张表的主键. 写一条SQL查询语句获取合作…

linux内核相关知识

参考https://www.cnblogs.com/xdyixia/p/9248240.html linux内核启动过程 一个嵌入式 Linux 系统从软件角度看可以分为四个部分&#xff1a;引导加载程序&#xff08;Bootloader&#xff09;&#xff0c;Linux 内核&#xff0c;文件系统&#xff0c;应用程序。其中 Bootloade…

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

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

leetcode10. 正则表达式匹配 一道没有解释的字符串dp困难题

给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符 * 匹配零个或多个前面的那一个元素 所谓匹配&#xff0c;是要涵盖 整个 字符串 s的&#xff0c;而不是部分字符串。 说明: s 可能为空&#xff0c;且只包含…

string相关库函数

char *strcat(char *dest, const char *src) 功能 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。 参数&#xff1a; dest – 指向目标数组&#xff0c;该数组包含了一个 C 字符串&#xff0c;且足够容纳追加后的字符串。 src – 指向要追加的字符串&#xff0c;该…

leetcode44. 通配符匹配 又是一道没有解释的字符串dp困难题

给定一个字符串 (s) 和一个字符模式 (p) &#xff0c;实现一个支持 ? 和 * 的通配符匹配。 ? 可以匹配任何单个字符。 * 可以匹配任意字符串&#xff08;包括空字符串&#xff09;。 两个字符串完全匹配才算匹配成功。 说明: s 可能为空&#xff0c;且只包含从 a-z 的小写…

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

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

java中如何生成随机数?

java中如何生成随机数&#xff1f; package com.test.util; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; public class CharacterUtils {/*** 第一种方法&#xff1b;length为产生的位数*/public static String getRandomString(int…

leetcode132. 分割回文串 II

给定一个字符串 s&#xff0c;将 s 分割成一些子串&#xff0c;使每个子串都是回文串。 返回符合要求的最少分割次数。 示例: 输入: "aab" 输出: 1 解释: 进行一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。 思路&#xff1a;dp[i]…

为什么需要智能指针

参考自https://www.cnblogs.com/round1/p/12906648.html 主要为了避免以下Bug: 内存泄露 &#xff1a;对象无法被释放&#xff0c;最常见的问题。野指针 &#xff1a; 指针指向未知。重复释放 : 顾名思义。 &#xff08;一&#xff09;内存泄露 : 1. 抛出异常&…

leetcode1068. 产品销售分析 I(SQL)

销售表 Sales&#xff1a; -------------------- | Column Name | Type | -------------------- | sale_id | int | | product_id | int | | year | int | | quantity | int | | price | int | -------------------- (sale_id, year) 是销售表…

多进程与多线程通信同步机制

多进程通信方式 管道pipe&#xff1a;管道是一种半双工的通信方式&#xff0c;数据只能单向流动&#xff0c;而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。命名管道FIFO&#xff1a;有名管道也是半双工的通信方式&#xff0c;但是它允许无亲缘关…

leetcode1069. 产品销售分析 II(SQL)

销售表&#xff1a;Sales -------------------- | Column Name | Type | -------------------- | sale_id | int | | product_id | int | | year | int | | quantity | int | | price | int | -------------------- sale_id 是这个表的主键。…

leetcode1070. 产品销售分析 III(SQL)

销售表 Sales&#xff1a; -------------------- | Column Name | Type | -------------------- | sale_id | int | | product_id | int | | year | int | | quantity | int | | price | int | -------------------- sale_id 是此表的主键。 …