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

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和端口。

截图来自: http://blog.csdn.net/xiongping_/article/details/47722049
这里写图片描述
关于sockaddr和sockaddr_in的区别:
http://blog.csdn.net/joeblackzqq/article/details/8258693
它们的联系:
这里写图片描述

udp socket 例子

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

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#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");    //htonl(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 <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#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:
这里写图片描述

tcp socket 例子

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

#include <stdio.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

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 <stdio.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

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 <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>

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 <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>

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.
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/theArcticOcean/article/details/52502427
文章标签: socket unix tcp udp
个人分类: linux网络编程
上一篇杂记 (2) —— linux and C
下一篇unix环境编程练习 (1)
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭