热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux下简单的socket通信实例

Linux下简单的socket通信实例  Ifyouspendtoomuchtimethinkingaboutathing,you’llnevergetitdone.       

Linux下简单的socket通信实例

 

 If you spend too much time thinking about a thing, you’ll never get it done.

                                                                                                                                      —Bruce Lee

      学习网络编程也一段时间了,刚开始看《UNIX网络编程》的时候,觉得这本厚厚的书好难啊!看到后来,发现并没有想象中的那么难。如果你是新手,建议你看到第二部分结束后,开始着手写代码。不写代码肯定是不行的。看100遍也没有敲一遍实现一遍来的清楚。敲完以后,带着问题去看书,你会更加有针对性。提高的速度是飞快的,这也是学习任何一本书、一门语言的唯一手段。

  写这个博客也是因为刚开始学的时候,查了好多别人写的东西,百度了以后,发现大家只是把所有的代码一贴。并没有讲解每个函数的功能。我甚至不知道哪个函数是哪个头文件下的。造成我对函数很不理解。下面我会对每个函数的功能,和它的头文件以及函数原型写出来,让大家参考,第一次写博客,有什么错误的地方,希望大家指正。可以在下面给我留言,也是我继续写下去的动力。

     我很希望和大家一起分享学习网络编程遇到的种种困难与不顺,也希望和大家一起讨论其中遇到的问题,一起成长,如果你刚开始打算学习网络编程,那这篇文章一定能给你一些帮助。

  我的邮箱:cvmimi_linhai@foxmail.com,转载请注明出处:http://www.cnblogs.com/yusenwu/p/4579167.html。

     关于怎样介绍这个简单的实例:(基本上涵盖了《UNIX网络编程》1-5章的内容,更深,更细的,需要我们再细读这本书

      --> 1、代码展示,功能介绍

  --> 2、首先介绍一下客户端和服务端中函数的功能以及函数的原形。

  --> 3、关于连接三次握手和TCP连接关闭时候的分组交换

      --> 4、IPv4、IPv6套接字的地址结构

  --> 5、一些好的学习网站总结

  --> 6、代码下载

  --> 7、总结

  --> 8、实现一个echo的实例,代码可以到Github上下载

client.c

 1  #include 
 2  #include 
 3  #include 
 4  #include 
 5  #include in.h>
 6  #include 
 7  #include <string.h>
 8  #include 
 9  #include 
10  #define MAXLINE 1024
11  int main(int argc,char **argv)
12  {
13  char *servInetAddr = "127.0.0.1";
14  int socketfd;
15  struct sockaddr_in sockaddr;
16  char recvline[MAXLINE], sendline[MAXLINE];
17  int n;
18  
19  if(argc != 2)
20  {
21  printf("client  \n");
22  exit(0);
23  }
24  
25  socketfd = socket(AF_INET,SOCK_STREAM,0);
26  memset(&sockaddr,0,sizeof(sockaddr));
27  sockaddr.sin_family = AF_INET;
28  sockaddr.sin_port = htons(10004);
29  inet_pton(AF_INET,servInetAddr,&sockaddr.sin_addr)
30 if((connect(socketfd,(struct sockaddr*)&sockaddr,sizeof(sockaddr))) <0 )
31 { 31 printf("connect error %s errno: %d\n",strerror(errno),errno); 32 exit(0); 33 } 34 35 printf("send message to server\n"); 36 37 fgets(sendline,1024,stdin); 38 39 if((send(socketfd,sendline,strlen(sendline),0)) <0) 40 { 41 printf("send mes error: %s errno : %d",strerror(errno),errno); 42 exit(0); 43 } 44 45 close(socketfd); 46 printf("exit\n"); 47 exit(0); 48 }

-执行:gcc client.c -o client    后启动 ./client 客户端程序 启动前先启动./server-----------------------------------------

 server.c

 1  #include 
 2  #include 
 3  #include 
 4  #include <string.h>
 5  #include in.h>
 6  #include 
 7  #include 
 8  #include 
 9  #include 
10  
11  #define MAXLINE 1024
12  int main(int argc,char **argv)
13  {
14  int listenfd,connfd;
15  struct sockaddr_in sockaddr;
16  char buff[MAXLINE];
17  int n;
18  
19  memset(&sockaddr,0,sizeof(sockaddr));
20  
21  sockaddr.sin_family = AF_INET;
22  sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
23  sockaddr.sin_port = htons(10004);
24  
25  listenfd = socket(AF_INET,SOCK_STREAM,0);
26  
27  bind(listenfd,(struct sockaddr *) &sockaddr,sizeof(sockaddr));
28  
29  listen(listenfd,1024);
30 
31  
32  printf("Please wait for the client information\n");
33  
34  for(;;)
35  {
36  if((cOnnfd= accept(listenfd,(struct sockaddr*)NULL,NULL))==-1)
37  {
38  printf("accpet socket error: %s errno :%d\n",strerror(errno),errno);
39  continue;
40  }
41  
42  n = recv(connfd,buff,MAXLINE,0);
43  buff[n] = '\0';
44  printf("recv msg from client:%s",buff);
45  close(connfd);
46  }
47  close(listenfd);
48  }

-执行:gcc server.c -o server    后启动 ./server 服务端程序-------------------------------------------------------

 

      > 1、代码展示,功能介绍

   上面这个简单的socket通信的代码要实现的功能:从客户端发送一条消息后,服务端接收这条消息,并在服务端显示(recv msg from client:****)。

   

  > 2、首先介绍一下客户端和服务端中函数的功能以及函数的原形。 

#include  
int socket(int family, int type, int protocol);   //指定期望的通信协议类型,返回的文件描述符和套接字描述符类似,我们成为套接字描述符,简称sockfd  

 family:协议族

family 说明
AF_INET IPv4协议 
AF_INET6 IPv6
AF_LOCAL Unix域协议(15章)
AF_ROUTE  路由套接字(18章)
AF_KEY 密钥套接字(19章)

 type:套接字的类型

type 说明
SOCK_STREAM(常用) 字节流套接字
SOCK_DGRAM 数据报套接字
SOCK_SEQPACKET  有序分组套接字
SOCK_RAW 原始套接字

 protocol:协议类型的常量或设置为0,以选择给定的family和type组合的系统默认值

protocol 说明
IPPROTO_TCP TCP传输协议
IPPROTO_UDP UDP传输协议
IPPROTO_SCTP SCTP传输协议

    

#include
int inet_pton(int family,const char *strptr,void *addrptr);//成功返回1,格式不对返回0,出错返回-1
//作用:p代表表达式 n代表数值 以后所写的所有代码中都有可能会需要这个函数,所以这个函数很重要
//将char所指向的字符串,通过addrptr指针存放
//他的反函数: inet_ntop()作用相反。可以百度查阅这个函数的功能。因为例子里我们没有涉及到,就不介绍了。以后用到的时候再说
//需要注意的是:当他发生错误的时候,errno的值会被置为EAFNOSUPPORT 关于errno值我们一会儿介绍。
#include  
int connect(int sockfd,const struct sockaddr* servaddr,socklen_t addrlen);//用connect函数来建立与TCP服务器的连接
#include
int close(int sockfd);//关闭socket,并终止TCP连接
#include 
int bind(int sockfd,const struct* myaddr,socklen_t addrlen);//把本地协议地址赋予一个套接字。也就是将32位的IPv4或128位ipv6与16位的TCP或者UDP组合。
#include
int listen(int sockfd,int backlog)//成功返回0,失败返回-1     listen函数仅由TCP服务器调用
//listen函数将会做两件事:
//1:我们在创建套接字的时候使用了socket函数,它创建的套接字是主动套接字,bind函数的功能就是通过这个将主动套接字,变成被动套接字,告诉内核应该接受指向这个套接字的请//求,CLOSED状态变成LISTEN状态
//2:本函数的第二个参数规定了内核要为该套接字排队的最大连接个数。
#include 
int accept(int sockfd,struct sockaddr* cliaddr,socklen_t *addrlen);//成功返回描述符,失败返回-1
//1、如果第二三个参数为空,代表了,我们对客户的身份不感兴趣,因此置为NULL;
//2、第一个参数为socket创建的监听套接字,返回的是已连接套接字,两个套接字是有区别的,而且非常重要。区别:我们所创建的监听套接字一般服务器只创建一个,并且一直存在。而内核会为每一个服务器进程的客户连接建立一个连接套接字,当服务器完成对某个给定客户的服务时,连接套接字就会被关闭。

  Linux下简单的socket通信实例

      Linux下简单的socket通信实例

  总结:我们学校的实验室是云计算实验室,有很多的集群,我在上面开了2台虚拟机,在两台Linux系统上跑。可以成功接收。只要将IP设置好即可,注意,关掉防火墙:service iptables stop;

  > 3、关于连接三次握手和TCP连接关闭时候的分组交换

  三次握手:

  为了更好的理解connect、bind、close三个函数,了解一下TCP连接的建立和终止是很有必要的。(请务必理解理解上面的所有的函数后,再看这节)。

  1、服务器首先必须被打开,等待准备接受外来的连接。我们上面的例子用到了socket、bind、listen这3个函数。之后,我们称为服务端被被动打开了。

  2、客户端是通过connect发起主动打开。

  Linux下简单的socket通信实例

      3、主动打开后,客户TCP发送了一个SYN(同步)分节,它告诉服务器客户将在连接中只发送的数据的初始序列号,SYN分节不携带数据。它发送的IP数据报,只有一个IP首部、一个TCP首部以及TCP选项。

  4、服务器必须确认(ACK)客户的SYN,同时自己也发送一个SYN分节,它含有服务器将在同一连接中发送的数据的初始序列号。服务器在单个分节中发送SYN和对客户SYN的ACK确认(+1)。

  5、客户必须确认服务器的SYN分节。

  上面的过程称为TCP的三次握手。

    注:SYN(synchronous)是TCP/IP建立连接时使用的握手信号。在客户机和服务器之间建立正常的TCP网络连接时,客户机首先发出一个SYN消息,服务器使用SYN+ACK应答表示接收到了这个消息,最后客户机再以ACK消息响应。这样在客户机和服务器之间才能建立起可靠的TCP连接,数据才可以在客户机和服务器之间传递

 

  TCP连接终止

  终止一个连接需要4个分节。

  1、通过调用close,我们执行主动关闭,TCP发送一个FIN(finish,表示结束),表示数据发送完毕。

  2、对端接收到FIN后,执行被动关闭。

    3、一段时候后,接收到文件结束符的应用进程,将调用close关闭它的套接字。于是套接字也发送一个了FIN。

  4、确认这个FIN ACK+1   下图很清楚的表达了。  

  5、我们也称它为TCP四次握手。

  Linux下简单的socket通信实例

      > 4、IPv4、IPv6套接字的地址结构

  IPv4地址结构: 

 1 struct in_addr {
 2    in_addr_t  s_addr;  
 3 };
 4 
 5 struct sockaddr_in {
 6    uint8_t sin_len; //无符号8位整型
 7    sa_family_t sin_famliy;  /*AF_INET*/
 8    in_port_t  sin_port;     
9 struct in_addr sin_addr; /*32位 IPv4 地址*/
10 char sin_zero[8]; /*unuse*/ 11 };
//头文件 #include
//sa_family_t和socklen_t 头文件 #include
//in_addr_t in_port_t 头文件 #include

 

  IPv6地址结构:

struct in6_addr {
   uint8_t  s6_addr[16];  
};

#define SIN6_LEN

struct sockaddr_in6 {
   uint8_t sin6_len;
   sa_family_t sin6_famliy;
   in_port_t  sin6_port;

   uint32_t sin6_flowinfo;
   struct in6_addr sin6_addr;

   uint32_t sin6_scope_id;   
};

 

  > 5、一些好的学习网站总结

  1、关于51CTO上的这个视频http://edu.51cto.com/course/course_id-903.html,我买了,但是讲的非常烂,建议大家不要购买。教课的老师也就是照着书念,还不如自己。浪费钱。

  2、http://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html 

       http://blog.csdn.net/hguisu/article/details/7445768/

     http://www.oschina.net/code/snippet_97047_675

           这几篇博客不错,能带你入门。

  > 6、代码下载

  Github: https://github.com/micwu/Demo

  > 7、总结

   学习之路是很蛮长的。想要学好,非常难,需要长期的积累。我也正在学习中。经过了很多的挫折,但是有理想,就一定能成功。希望大家想走Linux下服务器编程的同志们,一起加油吧。

  > 8、echo实现

  Linux下简单的socket通信实例

  代码下载:Github


推荐阅读
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • 本文由编程笔记#小编整理,主要介绍了关于数论相关的知识,包括数论的算法和百度百科的链接。文章还介绍了欧几里得算法、辗转相除法、gcd、lcm和扩展欧几里得算法的使用方法。此外,文章还提到了数论在求解不定方程、模线性方程和乘法逆元方面的应用。摘要长度:184字。 ... [详细]
  • 如何用JNI技术调用Java接口以及提高Java性能的详解
    本文介绍了如何使用JNI技术调用Java接口,并详细解析了如何通过JNI技术提高Java的性能。同时还讨论了JNI调用Java的private方法、Java开发中使用JNI技术的情况以及使用Java的JNI技术调用C++时的运行效率问题。文章还介绍了JNIEnv类型的使用方法,包括创建Java对象、调用Java对象的方法、获取Java对象的属性等操作。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
author-avatar
梁梁庆新
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有