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

标签: socket unix tcp udp
4310人阅读 评论(0) 收藏 举报
分类:

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.
查看评论

Linux的SOCKET编程详解

Linux的SOCKET编程详解 1. 网络中进程之间如何通信 进 程通信的概念最初来源于单机系统。由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进 程之间既互不干扰又...
  • hguisu
  • hguisu
  • 2012年04月10日 17:44
  • 253924

unix环境高级编程-------socket(套接字)

一、socket是什么?      socket就是用来通信的,本博客所讲的socket是基于tcp/ip协议的(当然还可以采用其他不同的网络协议来通信)?首先我们来了解一下tcp/ip协议:    ...
  • chenxun2009
  • chenxun2009
  • 2015年10月30日 00:10
  • 2630

Unix网络编程之socket编程(一)--socket入门简单程序

本程序实现客户端向服务器发送一个字符串,服务器将接收到的字符串回送给客户端。 // unp.h #ifndef _UNP_H #define _UNP_H #include #include #...
  • FreeeLinux
  • FreeeLinux
  • 2016年07月28日 19:46
  • 738

UNIX学习之路 一步一个脚印之socket编程/Socket的参数

1.创建Socket. 注意不同的系统下参数不一定相同,这里列出了所有要求的参数可用值。 另外注意不同的版本可以使用的参数也不相同,可以参考相关文档 参数a.地址族(与TCP/IP协议下的协议族...
  • ASKLW
  • ASKLW
  • 2017年03月08日 09:22
  • 326

unix socket编程

“一切皆Socket!” 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket。 ——有感于实际编程和开源项目研究。 我们深谙信息交流的价值,那网络中进程之间如何通信,...
  • clarkchenhot
  • clarkchenhot
  • 2016年07月15日 17:43
  • 2863

Unix Domain Socket的例子

下面是unix domain socket的服务器端和客户端的两个代码。/*  * =========================================================...
  • RichardYSteven
  • RichardYSteven
  • 2010年09月09日 22:28
  • 6478

本地通信实例(AF_UNIX) socket协议通信

转自:http://blog.csdn.net/bytxl/article/details/7965462   程序说明: 程序里包含服务端和客户端两个程序,它们之间使用 AF_UNIX 实现本...
  • ccwwff
  • ccwwff
  • 2015年05月13日 15:11
  • 6650

Unix域套接字(Unix Domain Socket)介绍

在Linux系统中,有很多进程间通信方式,套接字(Socket)就是其中的一种。但传统的套接字的用法都是基于TCP/IP协议栈的,需要指定IP地址。如果不同主机上的两个进程进行通信,当然这样做没什么问...
  • Roland_Sun
  • Roland_Sun
  • 2015年12月16日 15:48
  • 11762

Linux下的IPC-UNIX Domain Socket

一、 概述 UNIX Domain Socket是在socket架构上发展起来的用于同一台主机的进程间通讯(IPC),它不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用...
  • guxch
  • guxch
  • 2011年12月05日 10:05
  • 45938

本地socket unix domain socket

socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIXDomain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopb...
  • bingqingsuimeng
  • bingqingsuimeng
  • 2013年01月05日 18:18
  • 22947
    个人资料
    持之以恒
    等级:
    访问量: 37万+
    积分: 9423
    排名: 2422
    我的链接
    最新评论