socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIXDomain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。

UNIX Domain Socket是全双工的,API接口语义丰富,相比其它IPC机制有明显的优越性,目前已成为使用最广泛的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIX Domain Socket通讯的。

使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。

UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。

今天我们介绍如何编写Linux下的TCP程序,关于UDP程序可以参考这里:

http://blog.csdn.net/htttw/article/details/7519971

本文绝大部分是参考《Linux程序设计(第4版)》的第15章套接字

服务器端的步骤如下:

1. socket:      建立一个socket

2. bind:          将这个socket绑定在某个文件上(AF_UNIX)或某个端口上(AF_INET),我们会分别介绍这两种。

3. listen:        开始监听

4. accept:      如果监听到客户端连接,则调用accept接收这个连接并同时新建一个socket来和客户进行通信

5. read/write:读取或发送数据到客户端

6. close:        通信完成后关闭socket

客户端的步骤如下:

1. socket:      建立一个socket

2. connect:   主动连接服务器端的某个文件(AF_UNIX)或某个端口(AF_INET)

3. read/write:如果服务器同意连接(accept),则读取或发送数据到服务器端

4. close:        通信完成后关闭socket

上面是整个流程,我们先给出一个例子,具体分析会在之后给出。例子实现的功能是客户端发送一个字符到服务器,服务器将这个字符+1后送回客户端,客户端再把它打印出来

Makefile:

[plain] view plaincopy

  1. all: tcp_client.c tcp_server.c

  2. gcc -g -Wall -o tcp_client tcp_client.c

  3. gcc -g -Wall -o tcp_server tcp_server.c

  4. clean:

  5. rm -rf *.o tcp_client tcp_server

tcp_server.c:

[cpp] view plaincopy

  1. #include <sys/types.h>

  2. #include <sys/socket.h>

  3. #include <sys/un.h>

  4. #include <unistd.h>

  5. #include <stdlib.h>

  6. #include <stdio.h>

  7. int main()

  8. {

  9. /* delete the socket file */

  10. unlink("server_socket");

  11. /* create a socket */

  12. int server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);

  13. struct sockaddr_un server_addr;

  14. server_addr.sun_family = AF_UNIX;

  15. strcpy(server_addr.sun_path, "server_socket");

  16. /* bind with the local file */

  17. bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

  18. /* listen */

  19. listen(server_sockfd, 5);

  20. char ch;

  21. int client_sockfd;

  22. struct sockaddr_un client_addr;

  23. socklen_t len = sizeof(client_addr);

  24. while(1)

  25. {

  26. printf("server waiting:\n");

  27. /* accept a connection */

  28. client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &len);

  29. /* exchange data */

  30. read(client_sockfd, &ch, 1);

  31. printf("get char from client: %c\n", ch);

  32. ++ch;

  33. write(client_sockfd, &ch, 1);

  34. /* close the socket */

  35. close(client_sockfd);

  36. }

  37. return 0;

  38. }

tcp_client.c:

[cpp] view plaincopy

  1. #include <sys/types.h>

  2. #include <sys/socket.h>

  3. #include <sys/un.h>

  4. #include <unistd.h>

  5. #include <stdlib.h>

  6. #include <stdio.h>

  7. int main()

  8. {

  9. /* create a socket */

  10. int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);

  11. struct sockaddr_un address;

  12. address.sun_family = AF_UNIX;

  13. strcpy(address.sun_path, "server_socket");

  14. /* connect to the server */

  15. int result = connect(sockfd, (struct sockaddr *)&address, sizeof(address));

  16. if(result == -1)

  17. {

  18. perror("connect failed: ");

  19. exit(1);

  20. }

  21. /* exchange data */

  22. char ch = 'A';

  23. write(sockfd, &ch, 1);

  24. read(sockfd, &ch, 1);

  25. printf("get char from server: %c\n", ch);

  26. /* close the socket */

  27. close(sockfd);

  28. return 0;

  29. }

如果我们首先运行tcp_client,会提示没有这个文件:

因为我们是以AF_UNIX方式进行通信的,这种方式是通过文件来将服务器和客户端连接起来的,因此我们应该先运行tcp_server,创建这个文件,默认情况下,这个文件会创建在当前目录下,并且第一个s表示它是一个socket文件

程序运行的结果如下图:

下面我们详细讲解:

1.我们调用socket函数创建一个socket:

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

domain:指定socket所属的域,常用的是AF_UNIX或AF_INET

AF_UNIX表示以文件方式创建socket,AF_INET表示以端口方式创建socket(我们会在后面详细讲解AF_INET)

type:指定socket的类型,可以是SOCK_STREAM或SOCK_DGRAM

SOCK_STREAM表示创建一个有序的,可靠的,面向连接的socket,因此如果我们要使用TCP,就应该指定为SOCK_STREAM

SOCK_DGRAM表示创建一个不可靠的,无连接的socket,因此如果我们要使用UDP,就应该指定为SOCK_DGRAM

protocol:指定socket的协议类型,我们一般指定为0表示由第一第二两个参数自动选择。

socket()函数返回新创建的socket,出错则返回-1

2.地址格式:

常用的有两种socket域:AF_UNIX或AF_INET,因此就有两种地址格式:sockaddr_un和sockaddr_in,分别定义如下:

[cpp] view plaincopy

  1. struct sockaddr_un

  2. {

  3. sa_family_t sun_family;  /* AF_UNIX */

  4. char sun_path[];         /* pathname */

  5. }

  6. struct sockaddr_in

  7. {

  8. short int sin_family;          /* AF_INET */

  9. unsigned short int sin_port;   /* port number */

  10. struct in_addr sin_addr;       /* internet address */

  11. }

其中in_addr正是用来描述一个ip地址的:

[cpp] view plaincopy

  1. struct in_addr

  2. {

  3. unsigned long int s_addr;

  4. }

从上面的定义我们可以看出,sun_path存放socket的本地文件名,sin_addr存放socket的ip地址,sin_port存放socket的端口号

3.创建完一个socket后,我们需要使用bind将其绑定:

int bind(int socket, const struct sockaddr * address, size_t address_len)

如果我们使用AF_UNIX来创建socket,相应的地址格式是sockaddr_un,而如果我们使用AF_INET来创建socket,相应的地址格式是sockaddr_in,因此我们需要将其强制转换为sockaddr这一通用的地址格式类型,而sockaddr_un中的sun_family和sockaddr_in中的sin_family分别说明了它的地址格式类型,因此bind()函数就知道它的真实的地址格式。第三个参数address_len则指明了真实的地址格式的长度。

bind()函数正确返回0,出错返回-1

4.接下来我们需要开始监听了:

int listen(int socket, int backlog)

backlog:等待连接的最大个数,如果超过了这个数值,则后续的请求连接将被拒绝

listen()函数正确返回0,出错返回-1

5.接受连接:

int accept(int socket, struct sockaddr * address, size_t * address_len)

同样,第二个参数也是一个通用地址格式类型,这意味着我们需要进行强制类型转化

这里需要注意的是,address是一个传出参数,它保存着接受连接的客户端的地址,如果我们不需要,将address置为NULL即可。

address_len:我们期望的地址结构的长度,注意,这是一个传入和传出参数,传入时指定我们期望的地址结构的长度,如果多于这个值,则会被截断,而当accept()函数返回时,address_len会被设置为客户端连接的地址结构的实际长度。

另外如果没有客户端连接时,accept()函数会阻塞

accept()函数成功时返回新创建的socket描述符,出错时返回-1

6.客户端通过connect()函数与服务器连接:

int connect(int socket, const struct sockaddr * address, size_t address_len)

对于第二个参数,我们同样需要强制类型转换

address_len指明了地址结构的长度

connect()函数成功时返回0,出错时返回-1

7.双方都建立连接后,就可以使用常规的read/write函数来传递数据了

8.通信完成后,我们需要关闭socket:

int close(int fd)

close是一个通用函数(和read,write一样),不仅可以关闭文件描述符,还可以关闭socket描述符
转载自:http://blog.csdn.net/bingqingsuimeng/article/details/8470029

本地socket通讯 -转相关推荐

  1. 基于TCP的Socket通讯

    基于 TCP 的 Socket 通讯 最近要实现两个机器之间基于 TCP 的 socket 通讯(个人使用 Python 实现),尝试了官方的 demo 代码后总是被拒绝连接,仔细研究了一下并成功建立 ...

  2. 试解析Tomcat运行原理(一)--- socket通讯(转)

    关于这篇文章也确实筹划了很久,今天决定开篇写第一篇,说起tomcat首先很容易联想到IIS,因为我最开始使用的就是.net技术,我第一次使用asp写学生成绩管理系统后,很茫然如何让别人都能看到或者说使 ...

  3. C#.net同步异步SOCKET通讯和多线程总结(转)

    C#.net同步异步SOCKET通讯和多线程总结 来源:http://www.cnblogs.com/Silverlight_Team/archive/2009/03/13/1411136.html ...

  4. QT示例:基于TCP 点对多Socket通讯(server,clients)

    QT示例:基于TCP 点对多通讯(server,clients) 一.服务器server 二.客户端Client 下载:基于TCP 点对多Socket通讯 一.服务器server 因为对于客户端来说, ...

  5. 试解析Tomcat运行原理(一)--- socket通讯

    关于这篇文章也确实筹划了很久,今天决定开篇写第一篇,说起tomcat首先很容易联想到IIS,因为我最开始使用的就是.net技术,我第一次使用asp写学生成绩管理系统后,很茫然如何让别人都能看到或者说使 ...

  6. c语言socket通讯和进行进行大文件分片传输

    c语言socket通讯和进行进行大文件分片传输 server端代码和client端代码 在windows上创建Cygwing工程11socket-server,创建完成后启动工程看不到效果,必须放到l ...

  7. 全网最全的Java Socket通讯例子

    一.前言 Socket通讯在银行.图书馆,物联网应用较多,日常都是Http/Https居多.网上关于Java的比较完整的Socket编程例子屈指可数,参考价值不大.要么是短连接且只支持纯文本通讯:要么 ...

  8. Tomcat运行原理(一)--- socket通讯

    说起tomcat首先很容易联想到IIS,由此认识了IIS,它是一个web容器,天生的多线程,及时响应用户提交的请求返回html页面,这就是我了解的最初的web容器的功能,由此我们来认识tomcat也并 ...

  9. Java与C++Socket通讯注意

    2019独角兽企业重金招聘Python工程师标准>>> c++与java进行socket通信时注意事项 因为java发送的都是网络字节序(big-endium),而c++是主机字节序 ...

最新文章

  1. android 获取视频缩略图终极解决方案(ffmpeg)
  2. Can‘t connect to MySQL server on ‘localhost:3306‘ (10061)
  3. git只合并某一个分支的某个commit
  4. Azure虚拟机网站部署 防火墙设置
  5. mysql集群一:主从复制,通过mysql-proxy做负载均衡
  6. 鸿蒙公测第二期报名地址,鸿蒙2.0第二期公测报名入口及参加方法
  7. 系统学习深度学习(三十三)--Prioritized Replay DQN
  8. 程序员实用算法 源码_程序员必须知道的十大基础实用算法综述
  9. el-select传递多个参数_python函数是如何进行参数传递的
  10. 开发者论坛一周精粹(第六十三期) WHM自动脚本修复ssh问题
  11. uni-app做收货地址功能
  12. 棋牌搭建,APP新手教程
  13. java研发微博营销
  14. php 正则格式化图片,php利用正则表达式格式化电话号码的方法
  15. 路由器的两个端口接在同一个交换机上_什么是路由器交换机?路由器交换机介绍!...
  16. 微信视频号100w播放收入1000+的变现方式
  17. Android仿淘宝京东商品规格参数颜色筛选
  18. html div peidui,AirPods怎么删除配对过的设备 airpods可以和电脑连接的。
  19. 用R进行多元线性回归分析建模
  20. python与历史专业_python历史与基本类型

热门文章

  1. 用Winhex手工定位NTFS文件系统下的文件
  2. ajax教程 异步刷新验证,Ajax实现异步刷新验证用户名是否已存在的具体方法
  3. npm 切换源_nrm:npm包管理工具
  4. 《魔兽世界插件》教程---21点扑克游戏 Blackjack
  5. android源码分析(一) - 语言切换机制
  6. viewgroup的使用方法
  7. docker之快速部署gogs git
  8. 原型模式-prototype
  9. PHPStorm IDE 快捷键(MAC)
  10. leetcode 【 Add Two Numbers 】 python 实现