一 什么是套接字
  套接字是一种通信机制,凭借这种机制,客户/服务器系统的开发既可以在本地单机上进行,也可以跨网络进行。

二 套接字属性
  套接字的特性由3个属性确定,它们是:域,类型和协议
   1 套接字的域
    域指定套接字通信中的网络介质,最常见的套接字域是AF_INET,它指的是Internet网络,其底层的协议——网际(IP)只有一个地址族,它使用一种特定的方式来指定网络中的计算机,即人们常说的IP地址。

    AF_UNIX域是UNIX文件系统域,即使是一台还没联网的计算机上的套接字也可以使用这个域,这个域的底层协议是文件输入/输出,而它的地址就是文件名。
 
  2 套接字类型
    因特网协议提供了两种通信机制:流和数据报。
    2.1 流套接字
       流套接字提供的是一个有序,可靠,双向字节流的连接,因此,发送的数据可以确保不会丢失,复制或乱序到达,并且在这一过程中发生的错误也不会显示出来。大的消息将被分片,传输,再重组。
       流套接字由类型SOCK_STREAM指定,它们是在AF_INET域中通过TCP/IP(TCP代表是传输控制协议,IP代表是网际协议)连接实现的。
    2.2 数据报套接字
     数据报套接字由类型SOCK_DGRAM指定,不建立和维持一个连接。它对可以发送的数据报的长度有限制。数据报作为一个单独的网络消息被传输,它可能会丢失,复制或乱序到达。
     数据报套接字是在AF_INET域中通过UDP/IP连接实现的,它提供的是一种无序的不可靠服务(UDP代表的是用户数据报协议)。
     数据报适用于信息服务中的“单次”查询,它主要用来提供日常状态信息或执行低优先级的日志记录。基于数据报的服务器通常不保留连接信息。
 
 三 套接字的连接过程


  1 创建套接字

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain,      //指定协议族
       int type,       //指定这个套接字的通信类型
       int protocol     //指定使用的协议,将该参数设置为0表示默认协议
      );

  以下是协议族:   AF_UNIX:UNIX域协议(文件系统本地套接字)
            AF_INET:ARPA因特网协议(UNIX网络套接字)
         AF_ISO:ISO标准协议
         AF_NS:施乐网络系统协议
         AF_IPX:Novell IPX协议
         AF_APPLETALK:Appletalk DDS
  socket系统调用返回一个描述符,当这个套接字连接到另一端的套接字后,我们就可以用read和write系统调用,通过这个描述符来在套接字上发送和接收数据了。    
 
  2 套接字地址
   每个套接字域都有其自己的地址格式,对于AF_UNIX域套接字来说,它的地址有结构sockaddr_un来描述,该结构定义在头文件sys/un.h中

#include <sys/un.h>
struct sockaddr_un{
sa_family_t sun_family;//AF_UNIX
char sun_path[];//pathname,长度限制为108个字符
};

  对于AF_INET域,套接字地址由结构sockaddr_in来指定,该结构定义在头文件netinet/in.h中, 一个AF_INET套接字由它的域,端口号和IP地址来完全确定。

#include <netinet/in.h>
struct sockaddr_in{
short int sin_family;         //AF_INET;
unsigned short int sin_port;    //端口号
struct in_addr sin_addr;      //IP地址
};

  IP地址结构in_addr被定义为:

struct in_addr{
unsigned long int s_addr;    //使用inet_addr(const char *cp)函数将一个点分十进制的IP转换成一个长整数型数
};

  3 命名套接字
   通过给套接字命名,可以让创建的套接字被其他进程使用

#include <sys/socket.h>
int bind(int socket,                //创建的socket
      const struct sockaddr *address,    //套接字地址地址,在AF_INET域中则是struct sockaddr_in类型,在AF_UNIX域中则是struct sockaddr_un类型
      size_t address_len                //地址结构的长度
     );                      //bind调用在成功时返回0,失败时返回-1并设置errno

  bind系统调用把参数address中的地址分配给与文件描述符socket关联的为命名套接字,地址结构的长度由参数address_len传递。


  errno的值              描述


  EBADF              文件描述符无效
  ENOTSOCK             文件描述符对应的不是一个套接字
  EINVAL                文件描述符对应的是一个已命名的套接字
  EADDRNOTAVAIL         地址不可用
  EADDRINUSE            地址已经绑定了一个套接字

  EACCESS             权限不足
  ENOTDIR,ENAMETOOLONG   表明选择的文件不符合要求


  4 创建套接字队列
  创建套接字队列能够保存服务器未处理的请求

#include <sys/socket.h>
int listen(int socket,     //socket文件标识符
       int backlog    //用来设置队列中可以容纳的未处理连接的最大数目,超过这个数目,往后的连接将被拒绝,导致客户的连接请求失败。
      );          //listen函数在成功时返回0,失败时返回-1

  5 客户请求连接
  客户程序通过在一个未命名套接字和服务器监听套接字之间建立连接的方法

#include <sys/socket.h>
int connect(int socket,                //指定的套接字将连接到参数address指定的服务器套接字
       const struct sockaddr* address,    //这个和服务器端的bind操作部分一样,看步骤2,3
       size_t address_len            //指定address指向的结构的长度
       );                     //成功时,connect调用返回0,失败时返回-1并设置errno

    errno值              描述


    EBADF            传递给socket参数的文件描述符无效
    EALREADY          该套接字上已经有一个正在进行中的连接
    ETIMEOUT          连接超时
    ECONNREFUSED       连接请求被服务器拒绝


  如果连接不能立刻建立,connect调用将阻塞一段超时时间,一旦这个超时时间到达,连接将被放弃,connect调用失败。但如果connect调用被一个信号中断,而该信号又得到了处理,connect调用还是会失败
  connect的阻塞特性可以通过设置该文件描述符的O_NONBLOCK标志来改变。

int flags=fcntl(socket,F_GETFL,);
fcntl(socket,O_NONBLOCK|flags);

  6 服务器接受连接

#include <sys/socket.h>
int accept(int socket,              //客户程序连接到由socket参数指定的套接字上
       struct sockaddr *address,     //客户的地址,如果我们不关心客户的地址,可以将address参数指定为空指针
       size_t *address_len        //客户地址的长度,如果客户地址的长度超过这个值,它将被截断。
      );

  accept系统调用只有当有客户程序试图连接到由socket参数指定的套接字上时才返回,这里的客户是指套接字队列中排在第一个的未处理的连接。
  一般情况下,如果套接字队列中没有未处理的连接,accept将阻塞(程序将暂停)直到有客户建立连接为止,和请求连接一样,可以通过使用fcntl函数对套接字文件描述符设置O_NONBLOCK标志
  当有未处理的客户连接时,accept函数将返回一个新的套接字文件描述符。

  7 关闭连接
  close系统用来结束套接字连接。

四 示例

服务器程序server.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h> int main(){
int server_sockfd,client_sockfd;
int server_len,client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
//为服务器创建一个未命名的套接字
server_sockfd=socket(AF_INET,SOCK_STREAM,);
//命名套接字
server_address.sin_family=AF_INET;
server_address.sin_addr.s_addr=inet_addr("127.0.0.1");
server_address.sin_port=;
server_len=sizeof(server_address);
bind(server_sockfd,(struct sockaddr *)&server_address,server_len);
//创建一个连接队列,开始等待客户进行连接
listen(server_sockfd,);
while(){
char ch;
printf("server waiting\n");
//接受一个连接
client_len=sizeof(client_address);
client_sockfd=accept(server_sockfd,(struct sockaddr*)&client_address,&client_len);
//对client_sockfd套接字上的客户进行读写操作
read(client_sockfd,&ch,);
ch++;
write(client_sockfd,&ch,);
close(client_sockfd);
}
}

客户程序client.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h> int main(){
int sockfd;
int len;
struct sockaddr_in address;
int result;
char ch='A';
//为客户创建一个套接字
sockfd=socket(AF_INET,SOCK_STREAM,);
//命名套接字,与服务器保持一致
address.sin_family=AF_INET;
address.sin_addr.s_addr=inet_addr("127.0.0.1");
address.sin_port=;
len=sizeof(address);
//将我们的套接字连接到服务器的套接字
result=connect(sockfd,(struct sockaddr*)&address,len);
if(result==-){
perror("oops:client1");
exit();
}
//现在就可以通过sockfd进行读写操作了
write(sockfd,&ch,);
read(sockfd,&ch,);
printf("char from server=%c\n",ch);
close(sockfd);
exit();
}

  

Linux学习笔记30——套接字的更多相关文章

  1. linux学习笔记之套接字

    一.基础知识. 1:套接字基础. 1,是通信端点的抽象. 2,在UNIX类系统中被当作是一种文件描述符. 3,套接字通信域. 域 描述 AF_INET IPV4因特网域 AF_INET6 IPV6因特 ...

  2. 网络协议学习笔记(五)套接字Socket

    概述 前面学习网络知识的时候写过一篇关于套接字的随笔见<JAVA SOCKET 详解>,现在本人正在系统的学习网络知识,现在除了温故知新之外,在详细的学习记录一下套接字的知识. Socke ...

  3. Linux 学习笔记

    Linux学习笔记 请切换web视图查看,表格比较大,方法:视图>>web板式视图 博客园不能粘贴图片吗 http://wenku.baidu.com/view/bda1c3067fd53 ...

  4. deepin linux学习笔记

    目录 deepin linux学习笔记 前言 linux常用命令 ls 显示文件夹内容 cd 切换当前目录 pwd 查看当前工作目录 mkdir 新建文件夹 rm 删除文件或文件夹 mv 移动文件 c ...

  5. (转)Linux最常用指令及快捷键 Linux学习笔记

    Linux最常用指令及快捷键 Linux学习笔记 原文:http://blog.csdn.net/yanghongche/article/details/50827478 [摘自 鸟叔的私房菜]--转 ...

  6. linux学习笔记2-linux的常用命令

    第一篇博客:linux学习笔记1-ubuntu的安装与基本设置 之中,已经介绍了如何安装linux操作系统,以及一些基本的设置修改. 本篇博客主要介绍linux中的一些常用的终端命令 ======== ...

  7. deepin linux 学习笔记(二)——文本编辑器

    目录 deepin linux 学习笔记(二)--文本编辑器 前言 nano 小巧的命令行编辑器 通用 编辑 定位 排版 配置 vim 思路独特的超级编辑器 命令模式 插入模式 底线模式(末行模式) ...

  8. linux学习笔记2 - linux常用命令

    转载请标注原链接:http://www.cnblogs.com/xczyd/p/5543731.html 第一篇博客:linux学习笔记1-ubuntu的安装与基本设置 之中,已经介绍了如何安装lin ...

  9. Linux 学习笔记之超详细基础linux命令 Part 1

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122   说明:主要是在REHL Server 6操作系统下进行的测试 --字符界面虚拟终端与图形界面之间的切 方法:[ ...

随机推荐

  1. CenOs安装中文输入法

    http://jingyan.baidu.com/album/d8072ac4434666ec95cefda1.html?picindex=2 查看链接

  2. [DEncrypt] RSACryption--RSA加密/解密字符串 (转载)

    点击下载 RSACryption.zip 这个类是关于加密,解密的操作,文件的一些高级操作1.RSACryption RSA 的密钥产生2.RSACryption RSA的加密函数3.RSACrypt ...

  3. Android手势解锁, 九宫格解锁

    给大家介绍一个很好用的手势解锁控件ShapleLocker, 废话不多先上效果图: 这是一个第三方库, 可自己根据UI需求替换图标: 圆圈, 小箭头等等.. github地址: http://pane ...

  4. Android工程师必会做的20道题

    一.单选题     (共7道题,每题5分) 1.使用AIDL完成远程service方法调用下列说法不正确的是 A.aidl对应的接口名称不能与aidl文件名相同 B.aidl的文件的内容类似java代 ...

  5. (转)VS自带工具:dumpbin的使用

    有时候我们想查看一个exe引用了哪些动态库,或者我们想看某个动态库包含哪些接口函数,这个时候可以使用dumpbin.exe工具: 1.输入Dumpbin -imports calldll.exe查看它 ...

  6. Oracle 11g 虚拟列 Virtual Column介绍

    Oracle 11G 虚拟列 Virtual Column Oracle 11G 在表中引入了虚拟列,虚拟列是一个表达式,在运行时计算,不存储在数据库中,不能更新虚拟列的值. 定义一个虚拟列的语法: ...

  7. java Junit 测试中异常处理

    错误提示: junit.framework.AssertionFailedError: No tests found in错误解决办法 用junit Test运行后,出现如下的错误:junit.fra ...

  8. python文件操作汇总

    1.创建文件 f = open(filename,'w+')

  9. demo_04绘制三角形

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. power designer中查看表sql去掉字段属性双引号设置

    把Database → Edit Current DBMS → General → Script → Sql → Format → CaseSensitivityUsingQuote设置为NO