Linux/UNIX套接字连接

套接字连接

套接字是一种通信机子。凭借这样的机制。客户/server系统的开发工作既能够在本地单机上进行。也能够夸网络进行。

套接字的创建和使用与管道是有差别的。由于套接字明白地将客户和server区分开来。

套接字连接:

首先,server应用程序用系统调用socket来创建一个套接字,它是系统分配给该server进程的类似文件描写叙述符的资源,它不能与其它进程共享。

接下来。server进程会给套接字起个名字。本地套接字的名字是Linux文件系统中的文件名称,对于网络套接字它的名字是与客户连接的特定网络有关的服务标识符。这个标识符同意Linux将进入的针对特定port号的连接转到正确的server进程。

我们用bind来给套接字命名。然后server进程就開始等待客户连接到这个命名的套接字。

系统调用listen的作用是。创建一个队列并将其用于存放来自客户的进入连接。server通过系统调用accept来接受客户的连接。

server调用accept时。它会创建一个与原有的命名套接字不同的新套接字。这个套接字仅仅用于与这个特定的客户进行通信,而命名套接字则被保留下来继续处理来自客户的连接。

基于套接字系统的client更简单。

客户首先调用socket创建一个未命名套接字,然后将server的命名套接字作为一个地址来调用connect与server建立连接。

套接字属性

套接字的特性由三个属性确定:域、类型和协议。套接字还用地址作为它的名字。地址的格式随域的不同而不同。每一个协议又能够使用一个或多个地址来定义格式。

套接字的域

域指定套接字通信中使用的网络介质。

最常见的套接字域是AF_INET,它指的是互联网络。其底层协议——网际协议仅仅有一个地址族。它使用一种特定的方式来指定网络中的计算机,即人们常说的IP地址。

server计算机上可能同一时候有多个服务正在执行。

客户能够通过IPport来指定一台联网机器上的某个特定服务。在系统内部,port通过分配一个唯一16位的整数来标识,在系统外部,则须要通过IP地址和port号的组合来确定。

套接字作为通信的终点。必须在開始通信之前绑定一个port。

套接字域还能够是AF_UNIX,即使一台还未联网的计算机上的套接字也能够使用这个域。这个域的底层协议就是文件输入/输出,而他的地址就是绝对路径的文件名称。

我们的服务器套接字的地址是server_socket。

套接字类型

一个套接字域可能有多种不同的通信方式,而每种通信方式又有不同的特性。

AF_UNIX域的套接字没有这种问题。由于他们提供一个可靠的双向通信路径。

因特网协议提供两种不同的服务:流和数据报

流套接字:

流套接字提供一个有序、可靠、双向字节流的连接。因此,发送的数据能够确保不会丢失、复制或乱序到达,而且在这一过程中发生的错误也不会显示出来。流套接字由类型SOCK_STREAM指定,他们是在AF_INET域中通过TCP/IP连接实现。

他们也是AF_UNIX域中最常见的套接字类型。

数据报套接字

由类型SOCK_DGRAM指定的数据报套接字不建立和维持一个连接。它对能够发送的数据报的长度有限制。

数据报作为一个单独的网络消息被传输,可能会丢失、复制或乱序到达。

数据报套接字是在AF_INET域中通过UDP/IP连接实现的,它提供的是一种无须的不可靠服务。但从紫云的角度来看,它们的开销比較小,由于不须要维持网络连接。

并且由于无需花费时间来建立。所以他们的速度也非常快。UDP代表的是数据报协议。

套接字协议

仅仅要底层的传输机制同意不止一个协议来提供要求的套接字类型。就能够为套接字选择一个特定的协议。

创建套接字

socket系统调用创建一个套接字并返回一个描写叙述符。该描写叙述符能够用来訪问该套接字。

#include<sys/types.h>

#include<sys/socket.h>

int socket(intdomain, int type, int protocol);

创建的套接字是一条通信线路的一个端点。

domain參数指定协议族,type參数指定这个套接字的通信类型。protocol參数指定使用的协议。

最常见的套接字是AF_UNIX和AF_INET。

前者用于实现UNIX文件系统的本地套戒指。后者用于网络套接字。

type取值包含SOCK_STREAM和SOCK_DGRAM。

通信所用的协议一般有套接字类型和套接字域决定,通常不须要进行选择。将protocol參数设置为0表示使用默认协议。

socket系统调用返回一个描写叙述符。

套接字地址

每一个套接字域都有其自己的格式。

对于AF_UNIX域套接字来说。它的地址由结构sockaddr_un来描写叙述,该结果定义在头文件sys/un.h中。

structsockrrd_un{

sa_family_t      sun_family;

char                    sun_path[];

};

此处sun_family指定地址类型。sun_path为文件名称来指定套接字地址。

在AF_INET域中,套接字地址由结构socketaddr_in来指定,该结构定义在文件netinet/in.h中,至少包括下面几个成员:

structsocket_in{

short int                                       sin_family;

unsigned short int             sin_port;

struct in_addr                    sin_addr;

};

IP地址结构in_addr定义为

struct in_addr{

unigned long int      s_addr;

};

IP地址中的四个字节组成一个32位的值,一个AF_INET套接字由它的域、IP地址和port号来全然确定。

命名套接字

要想让通过socket调用创建的套接字能够被其它进程使用,server就必须给该套接字命名。这样,AF_UNIX套接字就会关联到一个文件系统的路径名。AF_INET套接字结汇关联到一个IPport。

#include<sys/types.h>          /* See NOTES*/

#include <sys/socket.h>

int bind(intsockfd, const struct sockaddr *addr, socklen_t addrlen);

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

bind调用须要将一个特定的地址结构指针转化为指向通用地类型(struct sockaddr *)。

bind调用成功返回0,失败返回-1。

创建套接字队列

为了可以在套接字上接受进入的连接,server程序必须创建一个队列来保存未处理的请求。使用listen系统调用来实现这一工作。

#include<sys/types.h>          /* See NOTES*/

#include <sys/socket.h>

int listen(int sockfd, int backlog);

在套接字队列中,等待处理的进入连接的个数不能超过backlog这个数字。再往后的连接将被拒绝。

接受连接

#include <sys/types.h>          /* See NOTES */

#include <sys/socket.h>

int accept(int sockfd, struct sockaddr*addr, socklen_t *addrlen);

一旦server程序创建并命名了套接字后,它就能够通过accept系统调用来等待客户建立对该套接字的连接。

accept系统调用仅仅有当客户试图连接到由sockfd參数指定的套接字上时才返回。

这里的客户指,在套接字队列中排在第一个的未处理连接。accept函数将创建一个新套接字来和该客户进行通信,而且返回新套接字的描写叙述符。

新套接字的类型和server监听套接字类型一样。

套接字必须事先由bind调用命名,而且有listen调用给他分配一个连接队列。

连接客户的地址将被放入address參数指向的sockaddr结构中。

參数address_len指定客户结构的长度。假设客户地址的长度超过这个值,它将被截段。所以在调用accept之前,address_len必须被设置为预期的地址长度。

当这个调用返回时,address_len将被设置为连接客户地址结构的实际长度。

假设套接字队列中没有未处理的联结,accept将被堵塞直到有客户建立连接为止。能够通过对套接字文件描写叙述符设置O_NOBLOCK标志来改变这一行为,使用函数fcntl。

请求连接

客户通过一个在未命名套接字和server监听套接字之间建立连接的方法来连接到server。

#include <sys/types.h>

#include <sys/socket.h>

int connect(intsockfd, const struct sockaddr *addr, socklen_t addrlen);

參数sockfd指定的套接字将连接到參数addr指定的server套接字,addr指向的结构的长度由參数addrlen指定。

关闭套接字

能够通过close函数来终止server和客户上套接字的连接。

主机字节序和网络字节序

为了使不同计算机能够通过网络传输的多字节整数的值达成一致,须要一个网络字节序。

客户和server必须在传输之前,将它们的内部整数表示方式转换为网络字节序。

能够通过下面函数完毕这一工作。

#include<arpa/inet.h>

uint32_t htonl(uint32_t hostlong);

uint16_thtons(uint16_t hostshort);

uint32_tntohl(uint32_t netlong);

uint16_tntohs(uint16_t netshort);

htonl表示”host tonetwork ,long”。

网络信息

通过调用gethostent,能够找到给定计算机主机信息

#include<netdb.h>

Struct hostent *gethostent (void);

Void sethostent (int stayopen);

Void endhostent (void);

Struct hostent{

Char *h_name;

Char **h_aliases;

Inth_addrtype;

Inth_length;

Char **h_addr_list;};

从接口获得网络名字和网络号:

#include<netdb.h.

Struct netent * getnetbyaddr (uint32_t net,int type);

Struct netent * getnetbyname (const char *name);

Struct netent * getnetent (void);

Void setnetent (int stayopen);

Void endnetent (void);

Struct netent{

Char *n_name;

Char **n_aliases;

Intn_addrtype;

Uint32_t n_net;};

将协议名字和协议号採用下面函数映射

#include <netdb.h>

Struct protoent * getprotobyname (const char* name);

Struct protoent * getprotobynumber (intproto);

Struct protoent * getprotoent (void);

Void setprotoent (int stayopen);

Void endprotoent (void)。

Struct protoent{

Char *p_name;

Char **p_aliases;

Intp_proto;};

从一个服务名映射到一个port号,服务名

#include<netdb.h>

Struct servent * getservbyname (const char *name, const char * proto);

Struct servent * getservbyport (int port,const char * proto);

Struct servent * getservent( (void);

Void setervent (int stayopen);

Void endservent (void);

Struct servent{

Char *s_name;

Char **s_aliases;

Ints_port;

Char *s_proto;};

从一个主机名字和服务名字映射到一个地址

#include <sys/socket.h>

#include <netdb.h>

Int getaddrinfo (const char * restrict host,const char * restrict service, const struct addrinfo * restrict hint, structaddrinfo ** restrict res);

Void freeaddrinfo (struct addrinfo * ai);

Struct addrinfo{

Intai_flags;

intai_family;

Intai_socktype;

Intai_protocol;

Socklen_t ai_addrlen;

Structsockaddr * ai_addr;

Char *ai_canonname;

Structaddrinfo * ai_next;};

gai_strerror将返回的错误码转换成错误消息

#include<netdb.h>

Const char * gai_strerror (int error);

将地址转换成主机或者服务名

#include<sys/socket.h>

#include <netdb.h>

Int getnameinfo (const struct sockaddr *restrict addr, socklen_t alen, char * restrict host,socklen_t hostlen, char *restrict service, socklen_t servlen, unsigned int flags);

传输数据

发送数据:

#include <sys/types.h>

#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,

const struct sockaddr *dest_addr,socklen_t addrlen);

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

struct msghdr {

void         *msg_name;       /* optional address */

socklen_t     msg_namelen;    /* size of address */

struct iovec *msg_iov;        /* scatter/gather array */

size_t        msg_iovlen;     /* # elements in msg_iov */

void         *msg_control;    /* ancillary data, see below */

size_t        msg_controllen; /* ancillary databuffer len */

int           msg_flags;      /*flags on received message */

};

接收数据:

#include <sys/types.h>

#include <sys/socket.h>

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,

struct sockaddr *src_addr,socklen_t *addrlen);

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

套接字选项

#include<sys/types.h>          /* See NOTES*/

#include <sys/socket.h>

int getsockopt(int sockfd, int level, int optname,

void *optval, socklen_t*optlen);

int setsockopt(int sockfd, int level, int optname,

const void *optval,socklen_t optlen);

能够用以上函数来设定和获取套接字选项。

时间: 2024-10-12 02:26:04

Linux/UNIX套接字连接的相关文章

Linux编程---套接字

网络相关的东西几乎都是建立在套接字之上.所以这个内容对于程序员来说还是蛮重要的啊. 其实套接字也就是一个特殊的设备文件而已,我始终不能明白为什么要叫套接字.这么个奇怪的名字.不过还是就这样算了吧.关键还是编程上.由于其重要性,我还是写的详细一点吧. 一.套接字 核心函数: int  socket(int domain,int type,int protocol); 这个函数在通信域domain中创建一个类型为type,使用协议protocol的套接字.并且返回一个描述字,也就是相当于打开了一个特

Linux 原始套接字--myping的实现

一.套接字的类型 A.流套接字(SOCK_STREAM) 用于提供面向连接.可靠的数据传输服务,其使用传输层的TCP协议 B.数据报套接字(SOCK_DGRAM) 用于提供一个无连接.不可靠的服务,其使用传输层上的UDP协议 C.原始套接字(SOCK_RAM) 原始套接字是相对表中套接字(即前面两种套接字)而言的.它与标准套接字的区别是原始套接字可以读写内核没有处理的IP数据包,流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据. 所以要访问其他协议的数据必须使用原始套接字.

关于linux 原始套接字编程

关于linux 网络编程最权威的书是<<unix网络编程>>,但是看这本书时有些内容你可能理解的不是很深刻,或者说只知其然而不知其所以然,那么如果你想搞懂的话那么我建议你可以看看网络协议栈的实现. 函数原型是 int socket(int domain, int type, int protocol); 其中domain 中AF_INET , AF_UNIT 较为常用,分别创建inet 域套接字和unix域套接字,unix套接字与文件相关.平时80%用的套接字都是AF_INET.这

PHP Socket(套接字连接)扩展简介和使用方法

PHP socket扩展是基于流行的BSD sockets,实现了和socket通讯功能的底层接口,它可以和客户端一样当做一个socket服务器. 使用这些函数时请注意,虽然他们中有很多和C函数同名的,但声明却很可能不同.未避免混淆,请仔细阅读函数描述. 不熟悉socket编程的可以在Unix手册上找到很多有用的信息,网上也有很多C socket编程方面的教程,简单修改一下就可以应用于PHP socket编程. 第一步:开启socket 到php.ini开启extension=php_socke

TCP/IP网络编程 学习笔记_8 --优雅地断开套接字连接

基于TCP的半关闭 TCP中的断开连接过程比建立连接过程更重要,因为建立连接过程一般不会出现什么大的变数,但断开过程就有可能发生预想不到的情况,因此要准确的掌控. 单方面断开连接带来的问题 Linux的close函数和Windows的closesocket函数是完全断开连接.完全断开是指无法传输数据也不能接收数据.因此,一方这样直接断开连接就显得不太优雅了.如:主机A发送完最后的数据后,调用close函数单方断开了连接,那么最终,由主机B传输的,主机A必须接收的确认数据也销毁了(四次握手). 为

linux netlink套接字学习资料

理论: http://blog.csdn.net/unbutun/article/details/3394061 进一步深入: http://edsionte.com/techblog/archives/4134 http://edsionte.com/techblog/archives/4140 http://edsionte.com/techblog/archives/4134 实践: http://bbs.chinaunix.net/thread-3766684-1-1.html 附录代码

linux netlink套接字实现类似ss命令 ,统计套接字以及TCP信息

参考了 ss的源代码 以及 netlink相关资料:http://blog.csdn.net/scdxmoe/article/details/27711205 实现结果为: gcc netlink_dig_530_7.c -o netlink_dig_530_7 ./netlink_dig_530_7 state      family     l.addr     l.port       r.addr     r.rport LISTEN     AF_INET   localhost  

配置Nginx和php-fpm用Sock套接字连接时,找不到php-fpm.sock的原因

转载:http://www.cnblogs.com/zzyyxxjc/p/4361282.html php5.3之后的版本,php-fpm.conf里的listen的默认配置是127.0.0.1:9000,就不会生成php-fpm.sock,因此如果需要Nginx里的配置有链接tmp/php-fpm.sock的话,需要将listen的地址配置成和nginx的配置文件一致,同时保证这个路径已经存在,这样在启动./php-fpm的时候,会在对应路径上自动生成php-fpm.sock,例如: 让PHP

VMware报错:无法连接 MKS: 套接字连接尝试次数太多;正在放弃

环境: win10    VMware pro 14   Cent OS 7 问题详情: 报错:无法连接 MKS: 套接字连接尝试次数太多:正在放弃 解决方案: 1.关闭报错的虚拟机 2.打开控制面板->系统和安全->管理工具->服务 3.找到VMware Authorization Service,鼠标右键选择启动,然后就可以看到状态的改变 4.选中后鼠标右键属性中启动类型设置为自动.下次就会自启动 5.重新打开虚拟机,测试 原文地址:https://www.cnblogs.com/s