套接字
前几篇文章讲的进程间通信方式:管道、共享内存、消息队列等,都是依靠一台计算机系统的共享资源实现。这些资源包括文件系统空间、共享的的物理内存或消息队列,但只有在同一台主机上才能通过使用这些方法。那么在不同的主机如何实现进程间通信呢?
答案就是使用套接字,套接字(socket)是一种通信方式,便于理解,可以把套接字看做是:地址+端口。客户/服务器系统的开发工作既可以在本地单机上进行,也可以不同主机之间跨网络进行,而套接字可以同时实现这两种通信需求。下面用简单的例子讲一下套接字的用法。
1.套接字连接
(1)套接字属性
服务器计算机上可能同时有多个服务正在运行。客户可以通过IP端口指定一台联网机器上的某个特定服务。在系统内部,端口通过分配一个唯一的16位的整数来标识,在系统外部,则需要通过IP地址和端口号的组合来确定。套接字作为通信的重点,它必须绑定一个端口。
服务器在特定的端口等待客户的连接。知名服务所分配的端口号在所有Linux和UNIX机器上都是一样。它们通常小于1024。其中最后一个就是Web服务器的标准接口。一般情况下,小于1024的端口号都是为系统服务保留的,并且所服务的进程必须具有超级用户权限。
(2)套接字类型
一个套接字域可能有多种不同的通信方式,而每种通信方式又有其不同的特性。但是AF_UNIX域的套接字没有这样的问题,它们提供了一个可靠的双向通信路径。
因特网协议提供了两种通信机制:流(stream)和数据报。
• 流套接字
流套接字提供的是一个有序,可靠,双向字节流的连接。它是通过TCP/IP实现。
• 数据报套接字
由类型SOCK_DGRAM指定的数据包套接字不建立和维持一个连接。它提供的是一种无序的不可靠服务。它是通过UDP/IP实现。优点是开销小,速度快。
实例
以下提供一个简单的实例,这个例子中服务器程序一次只能为一个客户服务,他从客户那里读取一个字符,增加它的值,然后再把它写回去。
(1)客户程序client1.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int sockfd;
int len;
struct sockaddr_un address;
int result;
char ch = 'A';
/* Create a socket for the client. */
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
/* Name the socket, as agreed with the server. */
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "server_socket");
len = sizeof(address);
/* Now connect our socket to the server's socket. */
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result == -1) {
perror("oops: client1");
exit(1);
}
/* We can now read/write via sockfd. */
write(sockfd, &ch, 1);