Linux下的Socket编程大体上包括Tcp Socket、Udp Socket即Raw Socket这三种,其中TCP和UDP方式的Socket编程用于编写应用层的socket程序,是我们用得比较多的,而Raw Socket则用得相对较少,不在本文介绍范围之列。

TCP Socket

基于TCP协议的客户端/服务器程序的一般流程一般如下:

它基本上可以分为三个部分:

一、建立连接:

  • 服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于监听端口的状态
  • 客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服务器应答
  • 服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK段,服务器收到后从accept()返回。

二、传输数据:

建立连接后,TCP协议提供全双工的通信管道,服务器端和客户端根据协议可以通过read和write的反复调用实现数据的传输

三、关闭连接:

当数据传输已经完成后,服务器和客户端可以调用Close关闭连接,一端关闭连接后,另一端read函数则会返回0,可以根据这个特征来感应另一端的退出。

下面就以一个简单的EchoServer演示一下如何创建服务器端和客户端代码,其中和socket相关api都会高亮显示。

服务器端示例:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>
  8. #define MAXLINE 80
  9. #define SERV_PORT 8000
  10. int main(void)
  11. {
  12. char buf[MAXLINE];
  13. int listenfd = 0;
  14. listenfd = socket(AF_INET, SOCK_STREAM, 0);
  15. sockaddr_in servaddr = {0};
  16. servaddr.sin_family = AF_INET;
  17. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  18. servaddr.sin_port = htons(SERV_PORT);
  19. bind(listenfd, (sockaddr *)&servaddr, sizeof(servaddr));
  20. listen(listenfd, 20);
  21. printf("Accepting connections ...\n");
  22. while (1)
  23. {
  24. sockaddr_in cliaddr = {0};
  25. socklen_t cliaddr_len = sizeof(cliaddr);
  26. int connfd = accept(listenfd, (sockaddr *)&cliaddr, &cliaddr_len);
  27. char str[INET_ADDRSTRLEN];
  28. printf("connected from %s at PORT %d\n",
  29. inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
  30. ntohs(cliaddr.sin_port));
  31. while(true)
  32. {
  33. int count = read(connfd, buf, MAXLINE);
  34. if (count == 0)
  35. break;
  36. write(connfd, buf, count);
  37. }
  38. close(connfd);
  39. printf("closed from %s at PORT %d\n",
  40. inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
  41. ntohs(cliaddr.sin_port));
  42. }
  43. }

PS:这里需要注意的一下的是sock函数的第二个参数SOCK_STREAM,它表示是一个TCP连接,后面我们会介绍通过传入SOCK_DGRAM打开udp连接。

服务器端主体流程就是一个死循环,它接受一个socket连接,然后将其原封不动的返回给客户端,待客户端退出后,关闭socket连接,再次接受下一个socket连接。

客户端代码如下:

  1. #include <stdio.h>
  2. #include <arpa/inet.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #define MAXLINE 80
  8. #define SERV_PORT 8000
  9. #define MESSAGE "hello world"
  10. int main(int argc, char *argv[])
  11. {
  12. char buf[MAXLINE];
  13. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  14. sockaddr_in servaddr = {0};
  15. servaddr.sin_family = AF_INET;
  16. inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
  17. servaddr.sin_port = htons(SERV_PORT);
  18. if (0 != connect(sockfd, (sockaddr *)&servaddr, sizeof(servaddr)))
  19. {
  20. printf("connected failed");
  21. return 1;
  22. }
  23. write(sockfd, MESSAGE, sizeof(MESSAGE));
  24. int count = read(sockfd, buf, MAXLINE);
  25. printf("Response from server: %s\n",buf);
  26. close(sockfd);
  27. return 0;
  28. }

UDP Socket

典型的UDP客户端/服务器通讯过程如下图所示:

由于UDP不需要维护连接,程序逻辑简单了很多,但是UDP协议是不可靠的,实际上有很多保证通讯可靠性的机制需要在应用层实现,可能反而会需要更多代码。

典型的示例如下:

  1. /* server.cpp */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>
  6. #define MAXLINE 80
  7. #define SERV_PORT 8000
  8. int main(void)
  9. {
  10. char buf[MAXLINE];
  11. char str[INET_ADDRSTRLEN];
  12. int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  13. sockaddr_in servaddr = {0};
  14. servaddr.sin_family = AF_INET;
  15. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  16. servaddr.sin_port = htons(SERV_PORT);
  17. bind(sockfd, (sockaddr *)&servaddr, sizeof(servaddr));
  18. printf("Accepting connections ...\n");
  19. while (1)
  20. {
  21. sockaddr_in cliaddr;
  22. socklen_t cliaddr_len = sizeof(cliaddr);
  23. int count = recvfrom(sockfd, buf, MAXLINE, 0, (sockaddr *)&cliaddr, &cliaddr_len);
  24. if (count < 0)
  25. {
  26. printf("recvfrom error");
  27. continue;
  28. }
  29. printf("received from %s at PORT %d\n",
  30. inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
  31. ntohs(cliaddr.sin_port));
  32. sendto(sockfd, buf, count, 0, (sockaddr *)&cliaddr, sizeof(cliaddr));
  33. }
  34. }
  35. /* client.cpp */
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include <unistd.h>
  39. #include <netinet/in.h>
  40. #include <arpa/inet.h>
  41. #define MAXLINE 80
  42. #define SERV_PORT 8000
  43. int main(int argc, char *argv[])
  44. {
  45. char buf[MAXLINE];
  46. char str[INET_ADDRSTRLEN];
  47. int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  48. sockaddr_in servaddr = {0};
  49. servaddr.sin_family = AF_INET;
  50. inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
  51. servaddr.sin_port = htons(SERV_PORT);
  52. while (fgets(buf, MAXLINE, stdin) != NULL)
  53. {
  54. int count = sendto(sockfd, buf, strlen(buf), 0, (sockaddr *)&servaddr, sizeof(servaddr));
  55. if (count == -1)
  56. {
  57. printf("sendto error");
  58. return 0;
  59. }
  60. count = recvfrom(sockfd, buf, MAXLINE, 0, NULL, 0);
  61. if (count == -1)
  62. {
  63. printf("recvfrom error");
  64. return 0;
  65. }
  66. write(STDOUT_FILENO, buf, count);
  67. }
  68. close(sockfd);
  69. return 0;
  70. }

Linux高级编程--10.Socket编程的更多相关文章

  1. ZT Linux系统环境下的Socket编程详细解析

    Linux系统环境下的Socket编程详细解析 来自: http://blog.163.com/jiangh_1982/blog/static/121950520082881457775/ 什么是So ...

  2. Linux下的C Socket编程 -- server端的继续研究

    Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...

  3. Linux下的C Socket编程 -- server端的简单示例

    Linux下的C Socket编程(三) server端的简单示例 经过前面的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的一个端口上面去. 绑定socket ...

  4. Linux下的C Socket编程 -- 获取对方IP地址

    Linux下的C Socket编程(二) 获取域名对应的IP地址 经过上面的讨论,如果我们想要连接到远程的服务器,我们需要知道对方的IP地址,系统函数gethostbyname便能够实现这个目的.它能 ...

  5. Linux下的C Socket编程 -- 简介与client端的处理

    Linux下的C Socket编程(一) 介绍 Socket是进程间通信的方式之一,是进程间的通信.这里说的进程并不一定是在同一台机器上也有可能是通过网络连接的不同机器上.只要他们之间建立起了sock ...

  6. 第九章:Python高级编程-Python socket编程

    第九章:Python高级编程-Python socket编程 Python3高级核心技术97讲 笔记 9.1 弄懂HTTP.Socket.TCP这几个概念 Socket为我们封装好了协议 9.2 cl ...

  7. 多线程编程以及socket编程_Linux程序设计4chapter15

    看了Linux程序设计4中文版,学习了多线程编程和socket编程.本文的程序参考自Linux程序设计4的第15章. 设计了一个客户端程序,一个服务端程序.使用TCP协议进行数据传输. 客户端进程创建 ...

  8. 【Linux编程】socket编程

    套接字是通信端点的抽象.文件描写叙述符用open函数创建,而套接字描写叙述符用socket函数创建.socket函数原型例如以下: int socket(int domain, int type, i ...

  9. 学习笔记(10) : Socket 编程典型代码积累

    网络编程实现的机制:   服务器端: 申请一个socket 绑定到一个IP地址和端口上 开启侦听,等待接受连接   客户端: 申请一个socket 连接服务器(指明IP.端口)   服务器端: 接收到 ...

随机推荐

  1. 从混战到三足鼎立,外卖O2O下一个谁先出局?

    来自第三方数据挖掘和分析机构权威iiMedia Research(艾媒咨询)发布的<2016Q3中国在线餐饮外卖市场专题研究报告>显示,2016Q3中国在线餐饮外卖市场活跃用户分布方面,美 ...

  2. Rails下cloud datastore的使用

      Rails下cloud datastore的使用 背景 部门有一个项目要用Ruby做 WebAPI,DB使用关系型数据库Cloud Sql和非关系型数据库Cloud Datastore . 还不了 ...

  3. VS 2008 创建MFC程序对话框的步骤

    用过不少编程语言,可是刚开始学的时候最容易忘记一些简单的流程或者生疏了.那么这里就说说VS 2008 创建MFC程序对话框的步骤.我主要是android开发方面的.平时使用jni调用不少c++代码.所 ...

  4. NUnitForms 测试GUI应用程序的优秀工具

    著名的NUnit是单元测试的优秀工具,但是要在一个测试方法中启动GUI程序,比如Windows Form界面,这比较难做到.NUnitForms就是为解决这个问题产生的,它是NUnit的一个扩展程序, ...

  5. 携程Android App插件化和动态加载实践

    携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实 ...

  6. WebClient的异步处理

    using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Te ...

  7. NPOI 添加行

    IRow sourceRow = sheet1.GetRow(); ; i < dt.Rows.Count-; i++) { IRow row = sheet1.CreateRow( + i); ...

  8. 无线局域网络 WIFI/WAPI/WLAN区别浅析

    WIFI和WAPI的区别 既然WIFI和WAPI都是WLAN的传输协议,那么两者究竟都有怎样的区别? 首先第一点区别在于,两者的缔造者不一样.WIFI是又国外制定的一个协议,而WAPI是由中国制定的, ...

  9. 如何利用OCS缓存TomcatSession全局变量(转)

    转: 首先非常感谢阿里云给我们提供了一个如此省事的平台. 我们公司是一家物流公司,主要提供运输和仓储的服务.我们现在正在把我们的系统往阿里云迁移.当然,还在迁移过程中,所以还有很多是没办法现在说得太清 ...

  10. android 电量分析工具

    .参考文章:https://developer.android.com/studio/profile/battery-historian.html 这篇文章讲的是如果dump 电量日子文件batter ...