进程通信的方法有管道、命名管道、信号、消息队列、共享内存、信号量,这些方法都要求通信的两个进程位于同一个主机。
1.socket接口
函数原型:int socket(int protofamily, int so_type, int protocol);
- protofamily 指协议族,常见的值有:
AF_INET,指定so_pcb中的地址要采用ipv4地址类型
AF_INET6,指定so_pcb中的地址要采用ipv6的地址类型
AF_LOCAL/AF_UNIX,指定so_pcb中的地址要使用绝对路径名
当然也还有其他的协议族,用到再学习了 - so_type 指定socket的类型,也就是上面讲到的so_type字段,比较常用的类型有:
SOCK_STREAM
SOCK_DGRAM
SOCK_RAW - protocol 指定具体的协议,也就是指定本次通信能接受的数据包的类型和发送数据包的类型,常见的值有:
IPPROTO_TCP,TCP协议
IPPROTO_UDP,UPD协议
0,如果指定为0,表示由内核根据so_type指定默认的通信协议
2.bind接口
函数原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
bind函数就是给图三种so_pcb结构中的地址赋值的接口
- sockfd 是调用socket()函数创建的socket描述符
- addr 是具体的地址
- addrlen 表示addr的长度
AF_INET:
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
3.listen接口
函数原型:int listen(int sockfd, int backlog);
listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数
4.accept接口
函数原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。
示例代码:
server.c
#include<stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include<linux/in.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<stdlib.h>
int main()
{
int s_fd;
//1.socket
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1)//创建失败
{
perror("socket");
exit(-1);
}
struct sockaddr_in s_addr;//结构体
s_addr.sin_family = AF_INET;//协议
s_addr.sin_port = htons(8989);//端口号
//s_addr.sin_addr.s_addr = inet_aton("127.0.0.1");
inet_aton("192.168.0.102",&s_addr.sin_addr);
//2.bind
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
listen(s_fd,10);
//4.accept
int c_fd = accept(s_fd,NULL,NULL);
//5.read
//6.write
printf("conect\n");
while(1);
return 0;
}
编译:gcc server.c
运行流程:
a. ./a.out
b.
运行结果: