套接字编程相关函数(2:TCP套接字编程相关函数)

  

  1. 基本TCP客户/服务器程序的套接字函数

  

  2. socket函数

  为了执行网络I/O,一个进程必须做的第一件事就是调用socket函数,指定期望的通信协议类型。其定义如下:

#include <sys/socket.h>
int socket(int family, int type, int protocol);
// 返回:若成功则返回非负描述符,若失败则返回-1

其中:family参数指明协议族,它是图4-2中所示的某个常值。该参数也往往被称为协议域。

   type指明套接字类型,它是图4-3中所示的某个常值。

   protocol参数应设为图4-4所示的某个协议类型常值,或者设为0,以选择所给定family和type组合的系统默认值。

  在《UNIX网络编程 卷1》中,作者将该函数进行了进一步的包装:

 1 /* include Socket */
 2 int
 3 Socket(int family, int type, int protocol)
 4 {
 5     int  n;
 6
 7     if ( (n = socket(family, type, protocol)) < 0)
 8         err_sys("socket error");
 9     return(n);
10 }
11 /* end Socket */

  

  

  

  并非所有套接字family和type的组合都是有效的,图4-5给出了一些有效的组合和对应的真正协议。其中标“是”的项也是有效的,但还没找到便捷的缩略词。而空白项则是无效组合。

  

  3. connect函数

  TCP客户端用connect函数来建立与TCP服务器的连接。其定义如下:

#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
// 返回:若成功返回0,若出错返回-1

其中:sockfd是由socket函数返回的套接字描述符。

  第二个、第三个参数分别是一个指向套接字地址结构的指针和该结构的大小。关于套接字详细可见前边一博文套接字编程相关函数(1:套接字地址结构、字节序转换、IP地址转换)

  在《UNIX网络编程 卷1》中,作者将该函数进行了进一步的包装:

1 void
2 Connect(int fd, const struct sockaddr *sa, socklen_t salen)
3 {
4     if (connect(fd, sa, salen) < 0)
5         err_sys("connect error");
6 }

  客户端在调用函数connect前不必非得调用bind函数,因为如果需要的话,内核会确定源IP地址,并选择一个临时端口作为源端口。

  如果是TCP套接字,调用connect函数将激发TCP的三路握手过程,而且仅在连接建立成功或出错时才返回。具体出错的几种情况请见书中4.3节。

  4. bind函数

  bind函数把一个本地协议地址赋予一个套接字。对于网际网协议,协议地址是32位的IPv4地址或128位的IPv6地址与16位的TCP或UDP端口号的组合。函数定义如下:

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
// 返回:若成功则返回0,若出错则返回-1

其中,第二个参数是一个指向特定于协议的地址结构的指针,第三个参数是该地址结构的长度。对于TCP,调用bind函数可以指定一个端口号,或指定一个IP地址,也可以两者都指定,还可以两者都不指定。

  1)服务器在启动时会捆绑众所周知的端口。如果一个TCP客户或服务器未曾调用bind捆绑一个端口,当调用connect或listen时,内核就要为相应的套接字选择一个临时端口。对于TCP客户端来说,让内核来选择临时端口是正常的,除非应用需要预留端口;然而对于服务器来说却极为罕见,因为服务器是通过他们众所周知的端口被大家认识的。

  2)进程可以把一个特定的IP地址捆绑到它的套接字上,不过这个IP地址必须属于其所在主机的网络接口之一。对于TCP客户,这就为该套接字上发送的IP数据报指派了源IP地址。对于TCP服务器,这就限定该套接字只接收那些目的地为这个IP地址的客户连接。TCP客户通常不把IP地址捆绑到它的套接字上。当连接套接字时,内核将根据所用外出网络接口来选择源IP地址,而所用外出接口则取决于到达服务器所需的路径。如果TCP服务器没有把IP地址捆绑到它的套接字上,内核就把客户端发送的SYN的目的IP地址作为服务器的源IP地址。

  正如我们所说,调用bind可以指定IP地址或端口,可以两者都指定,也可以都不指定。图4-6汇总了如何根据预期的结果,设置sin_addr和sin_port或sin6_addr和sin6_port的值。

  

  如果指定端口号为0,那么内核就在bind调用时选择一个临时端口。然而如果指定IP地址为通配地址,那么内核等到套接字已连接(TCP)或已在套接字上发出数据报(UDP)时才选择一个本地IP地址。

  对于IPv4来说,通配地址由常值INADDR_ANY来指定,其值一般为0。它告知内核去选择IP地址。示例如下:

struct sockaddr_in servaddr;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);    /* wildcard */

  如此赋值对IPv4是可行的,因为IP地址是一个32位的值,可以用一个简单的数字常值表示(上例中为0),对于IPv6,我们就不能这么做了,因为128位的IPv6地址是存放在一个结构中的。(在C语言中,赋值语句的右边无法表示常值结构。)为了解决这个问题,我们改写为:

struct sockaddr_in6 serv;
serv.sin6_addr = in6addr_any;    /* wildcard */

/* notes */
#include <netinet/in.h>
extern const struct in6_addr in6addr_any;        /* :: */

  系统预先分配in6addr_any变量并将其初始化为常值INT6ADDR_ANY_INIT。头文件<netinet/in.h>中含有in6addr_any的extern声明。

  无论是网络字节序还是主机字节序,INADDR_ANY的值(为0)都一样,因此使用htonl并非必需。不过既然头文件<netinet/in.h>中定义的所有INADDR_常值都是按照主机字节序定义的,我们应该对任何这些常值都使用htonl。

  如果让内核来为套接字选择一个临时端口号,那么必须注意,函数bind并不返回所选择的值。实际上,由于bind函数的第二个参数有const限定词,它无法返回所选之值。为了得到内核所选择的这个临时端口值,必须调用函数getsockname来返回协议地址。

时间: 2024-12-23 19:29:33

套接字编程相关函数(2:TCP套接字编程相关函数)的相关文章

Unix网络编程之基本TCP套接字编程(上)

TCP客户/服务器实例 服务器程序 #include "unp.h" int main(int argc, char **argv) { int listenfd, connfd; pid_t childpid; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; listenfd = Socket(AF_INET, SOCK_STREAM, 0); //1 bzero(&servaddr, sizeof(servad

《网络编程》基于 TCP 套接字编程的分析

本节围绕着基于 TCP 套接字编程实现的客户端和服务器进行分析,首先给出一个简单的客户端和服务器模式的基于 TCP 套接字的编程实现,然后针对实现过程中所出现的问题逐步解决.有关基于 TCP 套接字的编程过程可参考文章<基本 TCP 套接字编程>.该编程实现的功能如下: (1)客户端从标准输入读取文本,并发送给服务器: (2)服务器从网络输入读取该文本,并回射给客户端: (3)客户端从网络读取由服务器回射的文本,并通过标准输出回显到终端: 简单实现流图如下:注:画图过程通信双方是单独的箭头,只

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

在进行套接字编程之前必须熟悉其地址结构,有关套接字的地址结构可参考文章<套接字编程简介>.基于 TCP 的套接字编程的所有客户端和服务器端都是从调用socket 开始,它返回一个套接字描述符.客户端随后调用connect 函数,服务器端则调用 bind.listen 和accept 函数.套接字通常使用标准的close 函数关闭,但是也可以使用 shutdown 函数关闭套接字.下面针对套接字编程实现过程中所调用的函数进程分析.以下是基于 TCP 套接字编程的流程图: socket 函数 套接

学习笔记——网络编程3(基于TCP协议的网络编程)

TCP协议基础 IP协议是Internet上使用的一个关键协议,它的全称是Internet Protocol,即Internet协议,通常简称IP协议. 使用ServerSocket创建TCP服务器 在两个通信实体没有建立虚拟链路之前,必须有一个通信实体先做出“主动姿态”,主动接收来自其他通信实体的连接请求. Java中能接收其他通信实体连接请求的类是ServerSocket,ServerSocket对象用于监听来自客户端Socket连接,如果没有连接,它将一直处于等待状态. ServerSoc

第4章 基本tcp套接字编程

4.1 各种套接字api(重要) 4.1.1 socket() 用于创建一个套接字描述符,这个描述符指明的是tcp还是udp,同时还有ipv4还是ipv6 #include <sys/socket.h>?int socket(int family, int type, int protocol);//成功返回描述符,错误-1 family主要是指明的协议族,AF_INET:ipv4.AF_INET6:ipv6 .AF_LOCAL:unix域协议.AF_ROUTE:路由套接字.AF_KEY秘钥套

Unix 网络编程(四)- 典型TCP客服服务器程序开发实例及基本套接字API介绍

写在开头: 在上一节中我们学习了一些基础的用来支持网络编程的API,包括"套接字的地址结构"."字节排序函数"等.这些API几乎是所有的网络编程中都会使用的一些,对于我们正确的编写网络程序有很大的作用.在本节中我们会介绍编写一个基于TCP的套接字程序需要的一些API,同时会介绍一个完整的TCP客户服务器程序,虽然这个程序功能相对简单,但确包含了一个客户服务器程序所有的步骤,一些复杂的程序也都是在此基础上进行扩充.在后面随着学习的深入,我们会给这个程序添加功能. 下面

【UNIX网络编程(二)】基本TCP套接字编程函数

基于TCP客户/服务器程序的套接字函数图如下: 执行网络I/O,一个进程必须做的第一件事就是调用socket函数,指定期望的通信协议类型. #include <sys/socket.h> int socket(int family, int type, int protocol);/*返回值:若成功则为非负描述符,若出错则为-1*/ socket函数成功时返回一个小的非负整数值,它与文件描述符类似,把它称为套接字描述符,简称sockfd.family参数指明协议族,被称为协议域.type参数指

【UNIX网络编程(四)】TCP套接字编程详细分析

引言: 套接字编程其实跟进程间通信有一定的相似性,可能也正因为此,stevens这位大神才会将套接字编程与进程间的通信都归为"网络编程",并分别写成了两本书<UNP1><UNP2>.TCP套接字编程是套接字编程中非常重要的一种,仔细分析,其实它的原理并不复杂.现在就以一个例子来详细分析TCP套接字编程. 一.示例要求: 本节中试着编写一个完成的TCP客户/服务器程序示例,并对它进行深入的探讨.该示例会用到绝大多数的基本函数,未用到但比较重要的函数会在后面的补充上

基本的TCP套接字编程

上图基本展示了TCP客户端与服务器编程的基本的流程. 1.面向连接编程(TCP) 面向连接的网络应用程序开发流程比较固定,需要开发者创建服务器与客户端两个应用程序,通过网络是想进程间的通讯. ●     服务器端流程 1        创建套接字(socket) 2        服务绑定(bind) 3        服务侦听(listen) 4        处理新到连接(accept) 5       数据收发(recv\send) 6       套接字关闭(close) ●     客