socket 编程-简单介绍

使用套接字除了可以实现网络间不同主机间的通信外,还可以实现同一主机的不同进程间的通信,且建立的通信是双向的通信。

socket进程通信与网络通信使用的是统一套接口,只是地址结构与某些参数不同。

其主要流程如下:

 

1.服务端首先初始化Socket(),然后和接口进行绑定bind()和监听listen(),然后调用accept()进行阻塞。
2.客户端初始化socket(),然后调用connect()与服务端进行连接,然后客户端负责发送请求,服务端接收并且处理请求。write(),read().在 UNIX/Linux 系统中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作。

记录常用的函数接口

 

一. 创建socket
int socket(int domain, int type, int protocol);

说明:
创建socket,类型为AF_LOCAL或AF_UNIX,表示用于进程通信:

参数:
domain:指定协议族,对于本地套接字来说,值必须设置为AF_UNIX枚举值;
type:指定套接字类型,可以被设置为SOCK_STREAM(流式套接字)活SOCK_DGRAM(数据报式套接字)
protocol:指定具体的协议,应被设置为0

返回值:
返回值为生成的套接字描述符。

注意:
对于本地套接字来说,流式套接字(SOCK_STREAM)是一个有顺序的、可靠的双向字节流,相当于在本地进程之间建立起一条数据通道;
数据报式套接字(SOCK_DGRAM)相当于单纯的发送消息,在进程通信过程中,理论上可能会有信息丢失、复制或者不按先后次序到达的情况,
但由于其在本地通信,不通过外界网络,这些情况出现的概率很小。


二. 设置socket参数

SOCK_STREAM式本地套接字的通信双方均需要有本地地址,其中服务器端的本地地址需要明确指定,指定方法是使用struct sockaddr_un类型的变量
struct sockaddr_un{
sa_family_t sun_family; // AF_UNIX
char sun_path[UNIX_PATH_MAX]; // 路径名
}

三. 绑定
int bind(int socket, const struct sockaddr *address, size_t address_len);

参数
socket:服务端套接字描述符
address:需要绑定的服务端本地地址
address_len:本地地址的字节长度

 

四. 监听
服务器端套接字创建完毕并赋予本地地址值(名称,本例中为CAN_SERVICE)后,需要进行监听,等待客户端连接并处理请求,监听使用 listen 系统调用,
int listen(int socket, int backlog);
参数
socket:表示服务器端的套接字描述符;
backlog 表示排队连接队列的长度(若有多个客户端同时连接,则需要进行排队);

五、阻塞等待
接受客户端连接使用accept系统调用,它们的原形如下:
int accept(int socket, struct sockaddr *address, size_t *address_len);
参数
address 表示当前连接客户端的本地地址,该参数为输出参数,是客户端传递过来的关于自身的信息;
address_len 表示当前连接客户端本地地址的字节长度,这个参数既是输入参数,又是输出参数。实现监听、接受和处理。


六. 连接
客户端需要 调用connect()连接到服务端,其函数原型如下:

int connect(int socket, const struct sockaddr *address, size_t address_len);
参数
socket:客户端的套接字描述符
address:当前客户端的本地地址,是一个 struct sockaddr_un 类型的变量
address_len:表示本地地址的字节长度

七. 数据交互

无论客户端还是服务器,都要和对方进行数据上的交互。一个进程扮演客户端的角色,另外一个进程扮演服务器的角色,
两个进程之间相互发送接收数据,这就是基于本地套接字的进程通信。

循环读取客户端发送的消息,当客户端没有发送数据时会阻塞直到有数据到来。如果想要多个连接并发处理,需要创建线程,
将每个连接交给相应的线程并发处理。接收到数据后,进行相应的处理,将结果返回给客户端。发送和接收数据要使用 write 和 read 系统调用,它们的原形为:
int read(int socket, char *buffer, size_t len);
int write(int socket, char *buffer, size_t len);

代码示例:

服务端代码

#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include "sys/types.h"
#include <sys/stat.h>
#include "string.h"
#include <arpa/inet.h>
#include <sys/un.h>

int main(int argc, char *argv[])
{
    int lfd ,ret, cfd;
    struct sockaddr_un serv, client;
    socklen_t len = sizeof(client);
    char buf[1024] = {0};
    int recvlen;

    //创建socket
    lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (lfd == -1) {
        perror("socket error");
        return -1;
    }

    //初始化server信息
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");
    unlink("server.sock");
    //绑定
    ret = bind(lfd, (struct sockaddr *)&serv, sizeof(serv));
    if (ret == -1) {
        perror("bind error");
        return -1;
    }

    //设置监听,设置能够同时和服务端连接的客户端数量
    ret = listen(lfd, 36);
    if (ret == -1) {
        perror("listen error");
        return -1;
    }

    //等待客户端连接
    cfd = accept(lfd, (struct sockaddr *)&client, &len);
    if (cfd == -1) {
        perror("accept error");
        return -1;
    }
    printf("=====client bind file:%s\n", client.sun_path);

    while (1) {
        recvlen = recv(cfd, buf, sizeof(buf), 0);
        if (recvlen == -1) {
            perror("recv error");
            return -1;
        } else if (recvlen == 0) {
            printf("client disconnet...\n");
            close(cfd);
            break;
        } else {
            printf("ser:recv buf %s\n", buf);
            send(cfd, buf, recvlen, 0);
        }
    }

    close(cfd);
    close(lfd);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    int lfd ,ret;
    struct sockaddr_un serv, client;
    socklen_t len = sizeof(client);
    char buf[1024] = {0};
    int recvlen;

    //创建socket
    lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (lfd == -1) {
        perror("socket error");
        return -1;
    }

    //给客户端绑定一个套接字文件
    client.sun_family = AF_LOCAL;
    strcpy(client.sun_path, "client.sock");
    unlink("client.sock");
    ret = bind(lfd, (struct sockaddr *)&client, sizeof(client));
    if (ret == -1) {
        perror("bind error");
        return -1;
    }

    //初始化server信息
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");
    //连接
    connect(lfd, (struct sockaddr *)&serv, sizeof(serv));

    while (1) {
        fgets(buf, sizeof(buf), stdin);
        send(lfd, buf, strlen(buf)+1, 0);

        recv(lfd, buf, sizeof(buf), 0);
        printf("cli:recv buf %s\n", buf);
    }

    close(lfd);
    return 0;
}

 

posted @ 2024-10-15 12:53  靖意风  Views(10)  Comments(0Edit  收藏  举报