套接字:
进程间通信的方法:可以在同一台机器或者网络上不同计算机上的进行通信,明确区分客户机和服务器。
对管道概念的扩展。
服务器端:
-
首先服务器 应用程序通过socket系统调用创建一个套接字,他是系统分配给该服务器进程的类似文件描述符的资源,不能和其他进程分享。
-
其次,服务器进程使用bind系统调用给套接字命名:
-
本地套接字的名字是linux文件系统的文件名, 一般将其放在/tmp或者/usr/tmp目录下
-
网络套接字的名字是与客户相连的特定网络有关的服务 标识符,此标识符允许 linux将进入的针对特定端口号的连接转到正确的服务器进程
-
-
接下来服务器进程开始等待客户链接到这个名字套接字,调用listen创建一个等待队列,以便来存放来自客户的进入连接
-
最后,服务器通过accept系统调用来接收客户端的连接,此时,会产生一个与原有的命名套接字不同的新套接字,他仅用于这个特定的客户通信,而命名套接字则被保留下来继续处理来自其他客户的连接
客户端:
-
调用socket创建一个未命名的套接字,将服务器的明明套接字作为一个地址来调用connect与服务器建立连接。
-
一旦建立连接,就可以想使用底层文件描述符那样来用套接字进行双向的数据通信。
套接字由三个属性决定:
- 域
- 类型
- 协议
域:
- 指定套接字通信中使用的网络介质,包括地址格式,最常用的以下两种方式:
- AF_INET, 即互联网络,基于IP协议, 并且每一个服务对应一个端口号,套接字地址由IP地址+端口号决定。
- AF_UNIX,基于本地机器,底层协议使用文件输入 /输出,地址为绝对路径的文件名。
类型:
- 一个套接字域可能有不同的通信方式, 每种通信方式有不同的特性。
- AF_UNIX域的套接字没有通信方面的问题,因为其基于文件系统,提供了一个可靠的双向通信通路。
- 在AF_INET域中,需要注意底层网络特性:
- 流套接字:由类型SOCK——STREAM指定, 基于TCP/I实现,提供一个有序、可靠、双向字节流的连接,发送的数据不会丢失、乱序、重复。大的消息会被分块、传输、重组,很像一个文件流。
- 数据报套接字:由SOCK_STREAM指定, 基于UDP/IP协议,不建立和维持可靠连接,开销小,服务器崩溃时不需要客户端重启,因为基于 数据报的服务器不保留连接信息。
协议:
- 讨论的重点为网络套接字不需要选择特定的协议,只要默认为0就可以。
套接字举例:
创建套接字:
/*socket系统调用创建一个套接字,并返回一个描述符,该描述符可以用来访 问这个套接字。创建的套接字是一条通信链路的一个端点。*/
#include <sys/types.h>
#include <sys/socket.h>
int socket( int domain, int type, int protocol);
//参数解释
domain : 指定域
type : 指定套接字的通信类型
protocol : 指定使用协议
功能描述:
-
客户端程序:创建一个未命名的套接字,然后把他连接到服务器套接字server_socket上,向服务器写一个字符,再读回经服务器处理后的一个字符。
-
服务器端程序:首先创建一个服务器套接字,绑定到一个名字,然后创建一个监听队列,接收来自客户端程序的连接。
-
服务端程序
//服务端程序
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
int main() {
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_un server_address;
struct sockaddr_un client_address;
unlink("server_socket"); server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0); server_address.sun_family = AF_UNIX;
strcpy(server_address.sun_path, "server_socket");
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
listen(server_sockfd, 5);
while(1) {
char ch; printf("server waiting\n");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_address, &client_len);
read(client_sockfd, &ch, 1); ch++;
write(client_sockfd, &ch, 1);
close(client_sockfd);
}
} //主函数结束
//客户端程序
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
int main() {
int sockfd; int len;
struct sockaddr_un address;
int result;
char ch = 'A';
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "server_socket");
len = sizeof(address);
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result == -1) {
perror("oops: client1");
exit(1);
}
write(sockfd, &ch, 1);
read(sockfd, &ch, 1);
printf("char from server = %c\n", ch);
close(sockfd);
exit(0);
}