欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

linux C ----- udp, tcp, unix socket通信简单例子

程序员文章站 2022-05-16 10:02:54
udp socket 相关知识 udp的程序设计可以分成客户端和服务器端两个部分。两者的主要差别在于对地址的绑定函数,客户端可以不用进行地质和端口的绑定。(客户端是随机拿一个大于1024的端口去连接...

udp socket

相关知识

udp的程序设计可以分成客户端和服务器端两个部分。两者的主要差别在于对地址的绑定函数,客户端可以不用进行地质和端口的绑定。(客户端是随机拿一个大于1024的端口去连接的)
和tcp相比,udp缺少connect(),listen(),accept()函数 【因为tcp面向连接,而udp是无连接的。】
服务端的udp:

动作 函数
创建 socket()
绑定 bind()
发送 sendto()
接收 recvfrom()
关闭 close()

客户端和服务端相比没有绑定bind()的步骤。

服务端的recvfrom是阻塞的,直到接收到数据。
关键词:数据包套接字,套接字文件描述符。

socket常见的套接字类型:
- af_inet(又称 pf_inet)是ipv4网络协议的套接字类型
- af_inet6 是ipv6网络协议的套接字类型
- af_unix 属于unix本地通信

socket常见的套接字选项:

sock_stream sock_dgram
数据流 数据包
有保障 无保障
面向连接 面向无连接
tcp/ip udp
    int s=socket(af_inet,sock_dgram,0);
    if(s==-1){
        perror("create socket: ");
        return -1;
    }
    struct sockaddr serv;
    serv.sin_family=af_inet;   
    serv.sin_addr.s_addr=htol(inaddr_any);  // 任意本地ip,网络字节序
    serv.sin_port=htos(port);  //网络字节序
    bind(s,(struct sockaddr*)&serv,sizeof(serv));  //绑定套接字和地址

解释“绑定套接字和地址”,实质上是指明发送数据的ip和端口。

linux C ----- udp, tcp, unix socket通信简单例子

它们的联系:
linux C ----- udp, tcp, unix socket通信简单例子

udp socket 例子

编写一个程序,使用udp通信,client是10.21.1.142, server是10.21.1.229,port是3000. client发送end能使得程序结束。
客户端:

#include 
#include 
#include 
#include 
#include 
#include 
#define port 3000

int main(){ 
        int s=socket(af_inet,sock_dgram,0);
        if(s==-1){
             perror("create socket error: ");
             exit(1);
        }
        struct sockaddr_in serv;
        bzero(&serv,sizeof(serv));
        serv.sin_family=af_inet;   
        serv.sin_addr.s_addr = inet_addr("10.21.1.229");    //htol(inaddr_any); 
        serv.sin_port=htons(port);
        char buff[105];
        int ret;
        while(1){
             ret=read(stdin_fileno,buff,105);
             if(ret==-1){
                  perror("read error: ");
                  break;
             }
             buff[ret]=0;
             sendto(s,buff,strlen(buff),0,(struct sockaddr *)&serv,sizeof(serv));
             if(strcmp(buff,"end\n")==0){
                  printf("client process end.\n");
                  break;
             }
             int addr_len=sizeof(serv);
             if((ret=recvfrom(s,buff,105,0,(struct sockaddr *)&serv,&addr_len))==-1){
                  perror("recvform error: ");
                  break;
             }
             buff[ret]=0;
             printf("receive message from server: %s",buff);
        }
        close(s);
        return 0;
}

服务端:

#include 
#include 
#include 
#include 
#include 
#include 
#define port 3000

int main(){ 
    int s=socket(af_inet,sock_dgram,0);
        if(s==-1){
        perror("create socket error: ");
        exit(1);
    }
    struct sockaddr_in serv,client;
    bzero(&serv,sizeof(serv));
    serv.sin_family=af_inet;   
    serv.sin_addr.s_addr=inet_addr("10.21.1.229");//htol(inaddr_any); 
    serv.sin_port=htons(port);  //网络字节序
    if(bind(s,(struct sockaddr*)&serv,sizeof(serv))==-1){//绑定套接字和地址
        perror("bind error: ");
        exit(1);
    }
    while(1){
        char buff[105];
        int addr_len=sizeof(client);
        int ret=recvfrom(s,buff,105,0,(struct sockaddr *)&client,&addr_len); // once success, we get client.
        if(ret==-1){
            perror("recvfrom error: ");
            break;
        }
        buff[ret]=0;
        if(strcmp(buff,"end\n")==0){
            printf("server process end.\n");
            break;
        }
        printf("receive message from client: %s",buff);
            ret=read(stdin_fileno,buff,sizeof(buff));
        if(ret<0){
            perror("read error: ");
            break;
        }
        if(sendto(s,buff,ret,0,(struct sockaddr *)&client,addr_len)==-1){
            perror("sendto error: ");
            break;
        }
    }
    close(s);
    return 0;
}

会话:

$ ./udp1 
hello, i'm client
receive message from server: i'm server, i got message.
oh, congratulation.
receive message from server: hahaha
end
client process end.
$ ./udp1 
receive message from client: hello, i'm client
i'm server, i got message.
receive message from client: oh, congratulation.
hahaha
server process end.

tcp socket

相关知识

通用的套接字地址

struct sockaddr
{
unsigned short int sa_family;
char sa_data[14];
};

用户和内核进行数据交互:
得到数据: recv(), accept()
传入数据: send(), bind()
表示地址长度的参数在得到数据的函数中是传地址的, 而在传入数据的函数则是传值的. (对比accept和bind就知道这是正确的.)
tcp server and client work as:
linux C ----- udp, tcp, unix socket通信简单例子

tcp socket 例子

编写tcp socket通信例子, 分为客户端和服务端部分,当客户端发送”end”时,结束程序.
tcp_server.c:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

const int port = 3000;
const int max = 10; /* biggest number of connected clients */
const char ip[] = "192.168.123.4";

int main(){
    int server_fd=socket(af_inet,sock_stream,0);
    if(server_fd == -1){
        perror("socket: ");
        return -1;
    }
    struct sockaddr_in server;
    bzero(&server,sizeof(server));
    server.sin_family=af_inet;
    server.sin_addr.s_addr=htonl(inaddr_any); //inet_addr(ip);   /*  both ways are ok. */
    server.sin_port=htons(port);
    if(bind(server_fd,(struct sockaddr *)&server,sizeof(server))==-1){
        perror("bind: ");
        return -1;
    }
    if(listen(server_fd,max) == -1){
        perror("listen: ");
        return -1;
    }

    struct sockaddr_in client;
    int client_len=sizeof(client);
    int conn = accept(server_fd, (struct sockaddr *)&client, &client_len); 
    if(conn == -1){
        perror("accept: ");
        return -1;
    }
    char buff[105];
    while(1){
        memset(buff,0,sizeof(buff));
        if(read(conn,buff,sizeof(buff)) == -1){
            perror("read: ");
            break;
        }
        if(strcmp(buff,"end\n") == 0){
            puts("the server process end. ");
            break;
        }
        printf("recv message from client: %s", buff);
        memset(buff,0,sizeof(buff));
        if(read(stdin_fileno,buff,sizeof(buff)) == -1){
            perror("read: ");
            break;
        }
        if(write(conn,buff,strlen(buff)) == -1){
            perror("send: ");
            break;
        }
    }
    close(conn);
    close(server_fd);
    return 0;
}

tcp_client.c:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

const int port = 3000;
const int max = 10; /* biggest number of client_fdected clients */
const char ip[] = "192.168.123.4";

int main(){
    int client_fd=socket(af_inet,sock_stream,0);
    if(client_fd == -1){
        perror("socket: ");
        return -1;
    }
    struct sockaddr_in server;
    bzero(&server,sizeof(server));
    server.sin_family=af_inet;
    server.sin_addr.s_addr=inet_addr(ip);
    server.sin_port=htons(port);
    if(connect(client_fd,(struct sockaddr *)&server,sizeof(server))==-1){
        perror("client_fdect: ");
        return -1;
    }
    char sends[105],recvs[105];
    while(1){
        read(stdin_fileno,sends,sizeof(sends));
        if(send(client_fd,sends,strlen(sends),0)==-1){
            perror("send: ");
            break;
        }
        if(strcmp(sends,"end\n") == 0){
            puts("the client end.");
            break;
        }
        memset(recvs,0,sizeof(recvs));
        if(read(client_fd,recvs,sizeof(recvs))==-1){
            perror("recv: ");
            break;
        }
        printf("recv message from server: %s",recvs);
        memset(sends,0,sizeof(sends));
    }
    close(client_fd);
    return 0;
}

会话:

./tcps
recv message from client: hello
i got your message.
recv message from client: ok, every thins seems good.
client, we works.
the server process end.

./tcpc
hello
recv message from server: i got your message.
ok, every thins seems good.
recv message from server: client, we works.
end
the client end.

unix socket

相关知识

unix域协议族用于同一台主机上客户机、服务器通信。
unix域中两种类型的套接字:字节流套接字(类似于tcp)、数据包套接字(类似于udp)。
unix域套接字的传输速度是tcp的两倍。
unix域套接字和传统套接字相比,他是用路径名来表示协议族的描述。
unix域地质结构:

#define unix_path_max   108
struct sockaddr_un {
    __kernel_sa_family_t sun_family; /* af_unix */
    char sun_path[unix_path_max];   /* pathname */
};

sun_family: af_unix (known as af_local)
sun_path: 必须是绝对路径,文件默认访问权限是0777

unix socket例子

一个客户端和服务器通信(本地)的例子. 当客户端发送end时,结束会话.
un_sock_serv.c:

#include 
#include 
#include 
#include 
#include 

const char path[]="/tmp/server";
int main(){
    int server_fd,client_fd;
    struct sockaddr_un server_addr, client_addr;
    unlink(path);
    server_fd = socket(af_unix,sock_stream,0);
    if(server_fd == -1){
        perror("socket: ");
        exit(1);
    }
    server_addr.sun_family=af_unix;
    strcpy(server_addr.sun_path,path);
    if(bind(server_fd,(struct sockaddr *)&server_addr,sizeof(server_addr))==-1){
        perror("bind: ");
        exit(1);
    }
    listen(server_fd,10);  //server listen most 10 requests.
    puts("server is listening: ");
    int client_len=sizeof(client_addr);
    client_fd=accept(server_fd,(struct sockaddr *)&client_addr,(int *)&client_len);
    if(client_fd == -1){
        perror("accept: ");
        exit(1);
    }
    char recv[105], send[105];
    int i;
    while(1){
        memset(recv,0,sizeof(recv));
        if(read(client_fd,recv,105)==-1){
            perror("read: ");
            break;
        }
        if(strcmp(recv,"end\n")==0){
            printf("the server process end.\n");
            break;
        }
        printf("recv message from client: %s",recv);
        memset(send,0,sizeof(send));
        if(read(stdin_fileno,send,sizeof(send))==-1){
            perror("read: ");
            break;
        }
        if(write(client_fd,send,strlen(send))==-1){
            perror("write: ");
            break;
        }
    }
    close(server_fd);
    unlink(path);
}

un_sock_client.c:

#include 
#include 
#include 
#include 
#include 

const char path[]="/tmp/server";
int main(){
    int server_fd,client_fd;
    struct sockaddr_un server_addr, client_addr;
    //unlink(path);
    server_fd = socket(af_unix,sock_stream,0);
    if(server_fd == -1){
        perror("socket: ");
        exit(1);
    }
    server_addr.sun_family=af_unix;
    strcpy(server_addr.sun_path,path);
    if(connect(server_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)) == -1){
        perror("connect: ");
        exit(1);
    }
    char recv[105],send[105];
    int i;
    puts("the client started, please enter your message: ");
    while(1){
        memset(send,0,sizeof(send));
        if(read(stdin_fileno,send,105)==-1){
            perror("read: ");
            break;
        }
        if(write(server_fd,send,strlen(send))==-1){
            perror("send: ");
            break;
        }
        if(strcmp(send,"end\n")==0){
            printf("the client process end.\n");
            break;
        }
        memset(recv,0,sizeof(recv));
        if(read(server_fd,recv,105)==-1){
            perror("recv: ");
            break;
        }
        printf("recv message from server: %s",recv);
    }
    close(server_fd);
    unlink(path);
    return 0;
}

会话:

$ ./exes
server is listening: 
recv message from client: hello, i'm client
i'm server, i get your message.
recv message from client: ok, it seems goods.
yeah, it works.
the server process is end.

$ ./exec
the client started, please enter your message: 
hello, i'm client
recv message from server: i'm server, i get your message.
ok, it seems goods.
recv message from server: yeah, it works.
end
the client process end.