网络通信 Socket

  实现网络应用时要先从网络提供的接口开始,几乎所有计算机系统都将网络协议的软件实现作为操作系统的一部分,因此网络应用程序编程接口(API)一般都是操作系统提供的。套接字接口Socket是大部分操作系统都支持的一种流行接口,为计算机本地应用提供接入网络的功能。

  Socket(套接字)可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个逻辑上的概念。它是网络环境中进程间通信的API,使用中的每一个套接字都有其类型和一个与之相连进程。通信时其中一个网络应用程序将要传输的一段信息写入它所在主机的 Socket中,该 Socket通过与网卡(NIC)相连的传输介质将这段信息送到另外一台主机的 Socket中,使对方能够接收到这段信息。 Socket是由IP地址和端口结合的,提供向应用层进程传送数据包的机制。socket把复杂的TCP/IP协议封装了起来,只要用好socket相关的函数即可完成网络通信。

Socket 类型

  socket主要提供了流(stream)和数据报(datagram)两种通信机制,即流socket和数据报socket。

  流socket基于TCP协议,是一个有序、可靠、双向字节流的通道,传输数据不会丢失、不会重复、顺序也不会错乱。

  数据报socket基于UDP协议,不需要建立和维持连接,可能会丢失或错乱。UDP不是一个可靠的协议,对数据的长度有限制,但是它的速度比较高。

流Socket 工作流程

  Socket在工作中分为客户端(Client)和服务端(Server)两部分:

服务端工作流程:
  1. 创建socket

    int socket(int domain, int type, int protocol)
    //domain表示将要使用的协议族,例如:AF_INET表示因特网协议族
    //type表示通信的语义,例如:SOCK_STREAM表示字节流、SOCK_DGRAM表示面向消息
    //protocol表示将要用到的特定协议,下面统一用0
    //返回值是该套接字的句柄(handle),即引用该套接字时使用的标识符
    
  2. 把IP地址和端口绑定到socket上

    int bind(int socket, struct sockaddr *address, int addr_len)
    //socket是被绑定套接字的标识符
    //address是包含本地服务器IP地址和TCP端口号的结构体
    //addr_len是address的size
    //绑定成功返回0
    
  3. 设置socket为监听模式

    int listen(int socket, backlog)
    //socket是被绑定套接字的标识符
    //backlog是该套接字允许连接的数量
    //设置成功返回0
    
  4. 接受客户端的连接请求

    int accept(int socket, struct sockaddr *address, int *addr_len)
    //socket是被绑定套接字的标识符
    //address是包含服务器IP地址和TCP端口号的结构体,建立连接后会被写入客户端的对应信息
    //addr_len是address的size
    //此函数是个阻塞操作,当建立连接时才返回,返回值是远程客户端的socket标识符
    
  5. 与客户端重复通信,直到客户端断开连接

    int send(int socket, char *message, int msg_len, int flags)
    //把message信息发送给对应socket的远程端,message长度为msg_len,flags统一为0int recv(int socket, char *buffer, int buf_len, int flags)
    //从对应socket的远程端接收最大size为buf_len的信息到buffer,flags统一为0
    
  6. 关闭socket,释放资源

    int close(int socket)
    
客户端工作流程:
  1. 创建socket(方法同上)

  2. 向服务端发起连接请求

    int connect(int socket, struct sockaddr *address, int addr_len)
    //socket是被绑定套接字的标识符
    //address是包含服务端服务器IP地址和TCP端口号的结构体
    //addr_len是address的size
    //此函数也是个阻塞操作,当建立连接时才返回,返回值是远程服务器的socket描述符
    
  3. 与服务端通信,数据发送完后断开连接(方法同上)

  4. 关闭socket,释放资源(方法同上)

C++代码示例

  编译环境:Ubuntu 20.04、g++ 9.3.0

Server:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>int main(int argc, char *argv[])
{if (argc != 2){printf("请输入端口号!\n\n");return -1;}// 第1步:创建服务端的socket。int listenfd;if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket");return -1;}// 第2步:把服务端用于通信的地址和端口绑定到socket上。struct sockaddr_in servaddr; // 服务端地址信息的数据结构。memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;                // 协议族,在socket编程中只能是AF_INET。servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 使用任意ip地址。//servaddr.sin_addr.s_addr = inet_addr("192.168.190.134"); // 使用指定ip地址。servaddr.sin_port = htons(atoi(argv[1])); // 指定通信端口。if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0){perror("bind");close(listenfd);return -1;}// 第3步:把socket设置为监听模式。if (listen(listenfd, 5) != 0){perror("listen");close(listenfd);return -1;}// 第4步:接受客户端的连接。int clientfd;                             // 客户端的socket。int socklen = sizeof(struct sockaddr_in); // struct sockaddr_in的大小struct sockaddr_in clientaddr;            // 客户端的地址信息。clientfd = accept(listenfd, (struct sockaddr *)&clientaddr, (socklen_t *)&socklen);printf("客户端(%s)已连接。\n", inet_ntoa(clientaddr.sin_addr));// 第5步:与客户端通信,接收客户端发过来的报文后,回复ok。char buffer[1024];while (1){int iret;memset(buffer, 0, sizeof(buffer));if ((iret = recv(clientfd, buffer, sizeof(buffer), 0)) <= 0) // 接收客户端的请求报文。{printf("通信结束!\n");break;}printf("对方:%s\n", buffer);if (!strcmp(buffer, "拜拜")){printf("\n通信结束!\n");break;}memset(buffer, 0, sizeof(buffer));printf("我:");scanf("%[^\n]", buffer);char c = getchar();if ((iret = send(clientfd, buffer, strlen(buffer), 0)) <= 0) // 向客户端发送响应结果。{printf("发送失败,通信结束!\n");break;}if (!strcmp(buffer, "拜拜")){printf("\n通信结束!\n");break;}}// 第6步:关闭socket,释放资源。close(listenfd);close(clientfd);
}
Client:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>int main(int argc, char *argv[])
{if (argc != 3){printf("请输入ip地址和端口!\n\n");return -1;}// 第1步:创建客户端的socket。int sockfd;if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket");return -1;}// 第2步:向服务器发起连接请求。struct hostent *h;if ((h = gethostbyname(argv[1])) == 0) // 指定服务端的ip地址。{printf("gethostbyname failed.\n");close(sockfd);return -1;}struct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(atoi(argv[2])); // 指定服务端的通信端口。memcpy(&servaddr.sin_addr, h->h_addr, h->h_length);if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) // 向服务端发起连接清求。{perror("connect");close(sockfd);return -1;}// 第3步:与服务端通信,发送一个报文后等待回复,然后再发下一个报文。char buffer[1024];int iret;while (1){memset(buffer, 0, sizeof(buffer));printf("我:");scanf("%[^\n]", buffer);char c = getchar();if ((iret = send(sockfd, buffer, strlen(buffer), 0)) <= 0) // 向服务端发送请求报文。{printf("\n发送失败,通信结束!\n");break;}if (!strcmp(buffer, "拜拜")){printf("\n通信结束!\n");break;}memset(buffer, 0, sizeof(buffer));if ((iret = recv(sockfd, buffer, sizeof(buffer), 0)) <= 0) // 接收服务端的回应报文。{printf("\n接收失败,通信结束\n");break;}printf("对方:%s\n", buffer);if (!strcmp(buffer, "拜拜")){printf("\n通信结束!\n");break;}}// 第4步:关闭socket,释放资源。close(sockfd);
}
效果:
Server

Client

【进程通信】Socket相关推荐

  1. select 实现类似多线程_linux进程通信--socket套接字(四)--多路IO转实现一个server对应多个client...

    先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题 一 why 在前 ...

  2. Linux进程通信-管道

    用户空间进程间通信不可以,如何解决?通过内核空间对象--通信方式 线程间通信?可以在用户空间进行通信,通过全局变量. 线程通信的思路:基于文件io(函数方式不一样) 由此发现,管道通信也如此 通信方式 ...

  3. Unix domain socket 简介(进程间通信,进程通信)

    Unix domain socket 又叫 IPC(inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信.socket 原本是为网络通讯设 ...

  4. ARM环境中的c语言socket进程通信-转

    近由于需要弄一些android底层的进程间通讯的东西,所以重温了一下linux的进程通信知识. 进程间通信有很多种方法,使用socket只是其中的一种方法,使用socket的好处呢,就是通用,代码可以 ...

  5. Linux之本地进程间Socket通信

    文章目录 一.Sokcet 二.Sokcet API (一).sockaddr 结构: (二).struct socketaddr_in : (三).Struct socketaddr_un (四). ...

  6. Day4:应用层——网络应用层内容概述、网络应用基本原理(体系结构、进程通信、套接字socket、应用层协议)、Web应用与HTTP

    加油!寒假偷博人 一.网络应用层内容概述. 1本篇内容:(原理.实例.编程) 网络应用体系结构 客户机/服务器  P2P  混合结构 网络应用的服务需求 可靠性 带宽 时延 Inte ...

  7. 守护进程通信之Socket

    前置文章 <创建Android守护进程(底层服务) > 前言 在文章 <创建Android守护进程(底层服务) > 中,学习了如何创建一个 Android 守护进程,但是这个进 ...

  8. 【并发编程七】C++进程通信——套接字(socket)_80行代码实现一个聊天软件

    [并发编程七]进程通信--套接字(socket)_80行代码实现一个聊天软件 一.简介 二.相关知识介绍 1.winsock1.h.winsock2.h 2.如何使用ws2_32.dll 3.WSAS ...

  9. Linux下进程通信知识点学习笔记(一)

    4种主要事件导致进程创建: 系统的初始化: 执行了正在运行的进程所调用的进程创建系统调用: 用户请求创建一个进程: 一个批处理作业的初始化: 进程的终止: 正常退出: 出错退: 严重错误: 被其他进程 ...

  10. 跨进程通信,到底用长连接还是短连接

    一个完整的软件系统大多数情况下是由多个进程共同协作进行的,哪怕它们在同一台服务器上.所以,进程之间如何进行高效的通信至关重要. 单个应用程序+单个数据库这套基础开发套餐我相信每个人都经历过,甚至在初期 ...

最新文章

  1. arXiv论文如何一键链接解读视频,这个浏览器扩展帮你实现
  2. 三大运营商齐发力大数据
  3. C语言迷题:有符号数与无符号数的问题(转)
  4. 省市地区表 mysql数据库
  5. gns3中两个路由器分别连接主机然后分析ip数据转发报文arp协议_ARP协议在同网段及跨网段下的工作原理...
  6. 俩台电脑怎么设置同一局域网_方法 | 把手机上的照片传到电脑上
  7. 《设计模式》模板设计方法——面条非常香
  8. DelphiBCB一线程序员开发经验
  9. kafka 常见问题( 持续更新... ... )
  10. UITableView 自带编辑删除 自己定义button
  11. mysql “Access denied for user 'root'@'localhost'
  12. Linux文件的三种特殊权限SUID、SGID、STICKY
  13. Windows下安装HDFView
  14. 新学期flag-适合每个人的专业课
  15. 图像处理中的数学原理详解
  16. 《大秦帝国三:崛起》 剧情简介和最新进展
  17. LeetCode 452 用最少的箭头射爆气球
  18. 【百度地图API】如何利用自己的数据制作社交地图?只显示可视区域内的标注
  19. Insomnia下载
  20. 要你命3000List30

热门文章

  1. 文字或者图片连续滚动
  2. HLSL中的MUL指令深层剖析
  3. ASP.NET上传文件对文件类型的高级判断
  4. UA MATH575B 数值分析下IV 带约束的优化
  5. Bochs调试Linux内核 - 定位内核中的变量或数据结构
  6. jdbc template 学习总结
  7. hihoCoder week17 最近公共祖先·三 lca st表
  8. ProjectManagement::Redmine备份与恢复
  9. .Net 4.0 (2)
  10. Transaction And Lock--事务中使用return会回滚事务吗?