1. 概述

存在三种套接字:流式套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)和原始套接字(SOCK_RAW)。

TCP套接字工作流程:

首先,服务器端启动进程,调用Socket创建一个基于TCP协议的流套接字描述符。

其次,服务进程调用bind命名套接字,将套接字描述符绑定到本地地址和本地端口上。

再次,服务器端调用listen,开始侦听客户端的Socket连接请求。

接下来,客户端创建套接字描述符,并且调用connect向服务器端提交连接请求。服务器端接收到客户端连接请求后,调用accept,接受并创建一个新的套接字描述符与客户端建立连接,然后原套接字描述符继续侦听客户端的连接请求。

客户端与服务器端新套接字进行数据传输,调用write或send向对方发送数据,调用read或recv接收数据。

在数据交流完毕后,双方调用close或者shutdown关闭套字。

  1. socket的创建

函数原型:

intsocket(int domain, int type, int protocol);

PS:在实际编程中,我们只使用AF_INET协议,如果需要与本地主机进程建立连接,只需把远程地址设定为“127.0.0.1”即可。

创建套接实例:

  1. 创建AF_INET协议族上的流套接字描述符。

socket(AF_INET,SOCK_STREAM, 0)

socket(AF_INET,SOCK_STREAM, TCP)

  1. 创建AF_INET协议族上的数据报套接字描述符。

socket(AF_INET,SOCK_DGRAM, 0)

socket(AF_INET,SOCK_DGRAM, UDP)

  1. socket的命名

函数bind命名一个套接字,它为该套接字描述符分配一个半相关属性,其原型如下:

intbind(int s, const struct sockaddr* name, int namelen);

套接字地址属性结构:

structsockaddr

{

u_shortsa_family; /*协议族*/

charsa_data[14] /*最多14字节的协议地址*/

}

每个协议族都定义了自己套接字属性结构,协议族AF_INET使用结构sockaddr_in描述套接字地址信息。

structsockaddr_in

{

shortsin_family; /*16位的地址协议族(AF_INET)*/

u_shortsin_port; /*16位的端口地址*/

structin_addr sin_addr; /*32位的IP地址*/

charsin_zero[8]; /*预留,保持sockaddr_in与结构sockaddr的长度相同*/

};

structin_addr

{

u_longs_addr;

}

IP地址转换:

unsignedlong inet_addr(char *ptr);

intinet_aton(char *ptr, struct in_addr *addrptr);

char*inet_ntoa(struct in_addr inaddr);//将IP地址的整数形式转换为字符串格式输出

字节顺序转换:

u_longhtonl(u_long hostlong);

u_shorthtons(u_short hostshort);

u_longntohl(u_long netlong);

u_shortntohs(u_short netshort);

“h”代表“host”,代表主机字节序

“n”代表“network”,代表网络字节序。

“l”代表“long”,代表32位整数

“s”代表“short”,代表16位整数

例子:命名套接字描述符s的协议为AF_INET,地址由系统自动指定,端口号为1000.

structsockaddr_in sockaddr1; /*申请地址结构空间*/

memset(&sockaddr,0, sizeof(sockaddr)); /*清空空间*/

sockaddr1.sin_family= AF_INET; /*指定为AF_INET协议族*/

sockaddr1.sin_addr.s_addr= htonl(INADDR_ANY); /*任何IP地址*/

sockaddr1.sin_port= htons(10000); /*端口号*/

bind(s,(struct sockaddr *)&sockaddr1, sizeof(sockaddr1));

  1. socket的侦听

函数原型:

intlisten(int s, int backlog);

PS:listen仅在流套接字中使用。上述参数分别表示套接字描述符和套接字接受连接的最大数目。

例:服务器端套接字s进入侦听,最多只能接收客户端的10条申请。

listen(s,10);

/*TCP服务器端套接字准备函数*/

intCreateSock(int *pSock, int nPort, int nMax)

{

structsockaddr_in addrin;

structsockaddr *paddr = (struct sockaddr*)&addrin;

ASSERT(pSock!= NULL && nPort > 0 && nMax > 0);

memset(&addrin,0, sizeof(addrin));

addrin.sin_family= AF_INET;

addrin.sin_addr.s_addr= htonl(INADDR_ANY);

addrin.sin_port= htons(nPort);

ASSERT((*pSock=socket(AF_INET,SOCK_STREAM,0)) > 0);

if(VERIFY(bind(*pSock,paddr,sizeof(addrin))>= 0)&& VERIFY(listen(*pSock,nMax) >=0))

return0;

VERIFY(close(*pSock)== 0);

return1;

}

  1. Socket的连接处理

函数原型:

intaccept(int s, struct sockaddr *addr, int *addrlen);

/*TCP服务器端接收连接函数*/

intAcceptSock(int *pSock, int nSock)

{

structsockaddr_in addrin;

intlSize;

ASSERT(pSock!= NULL && nSock > 0);

while(1)

{

lSize= sizeof(addrin);

memset(&addrin,0, sizeof(addrin));

if((*pSock= accept(nSock,(structsockaddr*)&addrin,&lSize))> 0)

return0;

elseif(errno == EINTR)

continue;

else

ASSERT(0);

}

}

  1. socket的关闭

函数原型:

intshutdown(int s, int how);

函数shutdown可以全部关闭或者部分关闭套接字描述符s的连接,参数how指定了套接字关闭的方式,取值含义如下:

How取值

描述

0

套接字不可读,系统将自动丢弃接收到的数据和留在缓冲区中的数据,进程不能再从套接字中接收通信数据

1

套接字不可写,系统将写缓冲区的数据发送完毕后关闭套接字写操作,进程不能再从套接字中发送通信数据

2

彻底关闭套接字的连接

shutdown是强制性关闭全部套接字连接,而函数close只将套接字访问计数器减1,当且仅当计数器值为0时,系统才真正地关闭套接字通信。

PS:利用close的这个特性,可以建立Socket通信的服务器端的并发管理:父进程首先创建侦听套接字,一旦接收到连接请求则创建新的套接字与客户连接,再fork子进程,随后父进程调用close关闭新创建的套接字后继续侦听,子进程则调用close关闭侦听套接字,全权负责与客户端的通信。

  1. Socket的连接申请

函数原型:

intconnect(int s, const struct sockaddr *name, int namelen);

/*********TCP客户端函数**********/

intConnectSock(int *pSock, int nPort, char *pAddr)

{

structsockaddr_in addrin;

longlAddr;

intnSock;

ASSERT(pSock!= NULL && nPort > 0 && pAddr != NULL);

/***创建TCP套接字描述符***/

ASSERT((nSock= socket(AF_INET, SOCK_STREAM, p)) > 0);

/***协议地址组包*****/

memset(&addrin,0, sizeof(addrin));

addrin.sin_family= AF_INET;

addrin.sin_addr.s_addr= inet_addr(pAddr);

addrin.sin_port= htons(nPort);

if(VERIFY(connect(nSock,(struct sockaddr *)&addrin, sizeof(addrin)) > = 0))

{

/***连接成功,返回套接字描述符***/

*pSock= nSock;

return0;

}

close(nSock);

return1;

}

  1. TCP数据的发送

套接字一旦连接上,就可以发送数据。

函数原型:

intsend(int s, const void *msg, int len, int flags);

flags标志:

MSG_OOB:发送外带数据

MSG_DONTROUTE:通知远程IP就在本地局域网内,消息中不加入跌幅消息

  1. TCP数据的接收

函数原型:

intrecv(int s, void *buf, int len, int flags);

flags标志:

MSG_OOB:接收外带数据

MSG_PEEK:以窥视方式接收数据,即只接收而不从缓冲区中删除数据,下一次调用recv或read仍然可以接收这些数据

MSG_WAITALL:函数阻塞直到读取len字节数为止。不过本地标志并并非完全阻塞,当进程接收到信号,套接字出错、连接中断或指定了MSG_PEEK等情况出现时函数仍然会提前返回

  1. 其他一些相关函数

structhostent *gethostbyname(const char *name);

structhostent *gethostbyaddr(const char *addr, int len, int type);

voidherror(const char *string);//不能使用perror

structservent *getservbyname(const char *name, const char *proto);

structservent *getservbyport(int port, const char *proto);

intgetsockname(int s, struct sockaddr *name, int *namelen);

intgetpeername(int s, struct sockaddr *name, int *namelen);

  1. 套接字选项

函数原型:

intgetsockopt(int s, int level, int optname, void *optval, int *optlen);

intsetsockopt(int s, int level, int optname, const void *optval, intoptlen);

相关选项说明:

  1. SO_DEBUG

本选项只支持TCP协议,当选项打开时,系统内核跟踪套接字发送和接收的全部TCP数据记录。

  1. SO_REUSEADDR和SO_REUSEPORT

当尝试将一个套接绑定到某个端口时,如果该端口已经被占用了,一般情况下,绑定会失败,如果设置了此选项,系统能够让套接字bind到正在使用的地址或端口上。

  1. SO_KEEPALIVE

本选项是周期性地测试套接字连接是否依然存在。

  1. SO_DONTROUT

本选项控制发送消息是否越过协议的路由机制,打开时套接字将绕过协议的路由机制发送的数据。

  1. SO_LINGER

当缓冲区中还有数据尚未发送时,套接字的默认关闭机制是系统将这些数据立即发送对方,但不等待对方确认接收马上关闭套接字。SO_LINGER可以改变这个设置,它的数据传递通过结构linger完成。linger的结构定义如下:

structlinger

{

intl_onoff;//选项开关

intl_linger;//延时时间

}

结构linger成员取值含义如下:

L_onoff

L_linger

关闭机制

0

忽略

默认关闭机制

非0

0

直接丢弃缓冲区,立即关关套接字

非0

非0

等待缓冲区数据发送完毕或者延时l_linger秒后关闭套接字。如果套接字非阻塞选项打开,则立即关闭

  1. SO_BROADCAST

控制能否发送套接字数据广播,只用于数据报套接字和支持广播信息的网络上。

  1. SO_OOBINLINE

此选项打开时允许外带数据留在输入队列中,此时函数read和recv可以在不指明MSG_OOB标志的情况下读取外带数据。

  1. SO_SNDBUF和SO_RCVBUF

每个套接都有一个发送缓冲区和接收缓冲区,这两个缓冲区由底层的协议使用,选项SO_SNDBUF可以改变发送缓冲区的大小,选项SO_RCVBUF可以改变接收缓冲区的大小。客户端必须在connect前设置SO_RCVBUF选项,服务器端必须在listen前设置SO_RCVBUF选项,才可以有效地更改缓冲区的容量大小。

  1. SO_SNDLOWAT和SO_RCVLOWAT

这两个选项分别可以改变最小发送数据量和最小接收数据量。

  1. SO_SNDTIMEO和SO_RCVTIMEO

这两个选项用于设置发送数据和接收数据设置一个超时时间。超时时间采用结构timeval描述。

  1. SO_TYPE

调用本选项可以获取套接字的类型,返回值为SOCK_STREAM、SOCK_DGRAM或SOCK_RAW等,此选项不能用于setsockopt中。

  1. SO_ERROR

调用本选项可以获取并且清除套接字错误,不能应用于函数setsockopt中。

转载于:https://my.oschina.net/fuyajun1983cn/blog/263937

专题 15 TCP套接字编程相关推荐

  1. 套接字编程---2(TCP套接字编程的流程,TCP套接字编程中的接口函数,TCP套接字的实现,TCP套接字出现的问题,TCP套接字多进程版本,TCP套接字多线程版本)

    TCP模型创建流程图 TCP套接字编程中的接口 socket 函数 #include <sys/types.h> /* See NOTES */ #include <sys/sock ...

  2. tcp套接字编程模型

    1. tcp套接字编程 用下面的一张图可以清楚表示: 下面的python实现也很清晰: server: def tcplink(sock, addr):print 'Accept new connec ...

  3. 《计算机网络:自顶向下方法(原书第6版)》一2.7 TCP套接字编程

    本节书摘来华章计算机<计算机网络:自顶向下方法(原书第6版)>一书中的第2章 ,第2.7节,(美)James F.Kurose Keith W.Ross 著 陈 鸣 译 更多章节内容可以访 ...

  4. 《网络编程》基本 TCP 套接字编程

    在进行套接字编程之前必须熟悉其地址结构,有关套接字的地址结构可参考文章<套接字编程简介>.基于 TCP 的套接字编程的所有客户端和服务器端都是从调用socket 开始,它返回一个套接字描述 ...

  5. 计算机网络实验4 - TCP套接字编程 - 点对点聊天 - 代码实现

    客户端 package chat;import java.io.IOException; import java.io.PrintStream; import java.net.Socket; imp ...

  6. 《UNIX网络编程 卷1:套接字联网API》学习笔记——基本TCP套接字编程

    UNIX网络编程--基本TCP套接字编程 socket 函数 connect 函数 bind 函数 listen 函数 accept 函数 fork 和 exec 函数 并发服务器 close 函数 ...

  7. UNIX环境编程(c语言)--套接字--基本TCP套接字编程

    目录 准备知识 字节序 字节序转换函数 字节操纵函数 地址转换函数 地址结构 基本TCP套接字编程 概要 socket函数 bind函数 listen函数 accept函数 connect函数 通信函 ...

  8. Experiment 0x1:TCP套接字编程

    Experiment 0x1:TCP套接字编程 文章目录 Experiment 0x1:TCP套接字编程 0x0 说明 0x1 要求 0x2 实现 0x3 源码 1- TCP服务端源码 2- TCP客 ...

  9. TCP套接字编程(C语言)

    本篇主要内容介绍: 介绍TCP套接字基本概念 介绍TCP套接字编程流程 基本TCP套接字函数介绍 1.TCP套接字基本概念(非官方解释,个人总结) 套接字是一种网络API,提供一种进程间的通信方法,使 ...

最新文章

  1. SQL Server Integration Services 包的开发与部署初探
  2. 爬虫请求库 requests
  3. c++ 或者 vc++中判断程序实例是否运行
  4. 原则,策略,规范也是构架的一部分
  5. CentOS,重启的常用命令
  6. 如何高效率学Web前端 怎么规划前端学习路线
  7. AOS编排语言系列教程(三):创建子网Subnet
  8. Kaggle新手入门之路(完结)
  9. C#面向对象 基础概念二十五个 (很基础,必须掌握的知识)
  10. Top 10 Security Issue Solution
  11. 微软卸载工具msicuu2(附带资源)
  12. 软件开发延期引发纠纷-律师随笔
  13. 华为RH5885H V3服务器采集日志
  14. 装了mysql电脑黑屏怎么办_电脑黑屏的原因,教你解决黑屏
  15. 【英语:语法基础】C4.日常对话-餐饮专题
  16. JAVA系列 IO流 知识结构整理 建立合理的知识框架逻辑 输入输出流 理顺你的思维架构Fileoutput inputStream FileWriter FIleReader结构整理
  17. 计算机病毒考试及答案,计算机病毒类考试题目以及参考答案.doc
  18. MATLAB中的一些函数
  19. 声音发生器、pwm、占空比
  20. python画生日_使用PYTHON制作一个生日查看器

热门文章

  1. 数组方法关于任意数字类型的数组求最大值解决办法
  2. asp.net mvc 简易上传功能
  3. Go 语言并发模型 Context
  4. 浏览器缓存浅解--记录备复习
  5. COGS2355 【HZOI2015】 有标号的DAG计数 II
  6. [swift]-使用JavaScript解决WKWebView无法发送POST参数问题
  7. 2016企业开发趋势:Lightbend关于JVM开发者的调查
  8. 多线程方式实现Socket通信
  9. Oracle Events事件
  10. 直接运行PowerShell脚本