socket网络编程

网络编程应用于多机通讯,如linux服务器跟安卓手机的通讯,跟ios的手机通讯,跟c51单片绩效的通讯等。

网络编程的要点

1.地址 (由IP地址跟端口号组成)

每个设备都有一个ip地址来标识。

 一台拥有ip地址的主机可以提供许多服务(如web服务,ftp服务等),主机在区分不同的网络服务中显然不能只靠IP地址来区分,还要加上端口号来进行区分。

2.协议(一种数据格式,简单来说就是确定双方交流的语言,不能说一个人讲英语,一个人讲汉语这样双方根本交流不起来)

socket 也叫套接字网络编程主要用 TCP/UDP 的协议 。

TCP/UDP 协议的区别:

TCP面向连接(如打电话你拨号后对方接通建立连接后就可以交流)

UDP是面向报文的(如发短息 ,它只负责发给对方,至于对方看没看到信息它不管)

每一条TCP连接只能点到点的,UDP支持一对一,一对多,多对一,多对多的交互通信

socket网络编程步骤:

 创建套接字

int socket( int domain , int type , int protocol )

 

domain:指明所使用的协议族,一般为AF_INET

type:指定socket的类型,TCP协议是SOCK_STREAM    

protocol:一般为0

 把ip地址和端口号绑定到套接字

int bind(  int sockfd  ,  const struct sockaddr *addr  ,  socklen_t addrlen )

 

sockfd:socket函数返回的文件描述符

addr:含有本机IP地址及端口号等信息的指针

addrlen:一般为sizeof(struct sockaddr_in)

addr 一般都是用 struct sockaddr_in 类型来定义

struct sockaddr_in{
        sa_family_t       sin_family;                 //地址族(Address Family),也就是地址类型
        uint16_t             sin_port;                   //16位的端口号
        struct in_addr   sin_addr;                 //32位IP地址

        char                    sin_zero[8];             //不使用
};

struct in_addr{
        in_addr_t s_addr;    //32位IPv4地址
};

        

sin_portsin_addr 都必须是网络字节序,一般可视化的数字都是主机字节序

htons( )              将端口号由主机字节序转换为网络字节序的整数值。

inet_addr( )        将字符串的IP地址转化为一个网络字节序的整数值。

atoi ( )                 将把​​​​​​​字符串转换成长整型数

监听网络连接

int listen( int sockfd , int backlog )

        

sockfd:socket函数返回的文件描述符

backlog:指定在请求队列中允许的最大请求数

监听到有客户端接入,接受连接

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

   

sockfd: socket函数返回的文件描述符     

addr:     是一个指向struct sockaddr *的指针,里面有客户端的IP地址和端口号等信息,如果对客户的地址不感兴趣,那么可以把这个值设置为NULL

addrten:用来接受addr的结构的大小,它指明addr结构所占有的字节个数,同样的,它也可以被设置为NULL。

客户端连接服务器

 int connect( int sockfd , struct sockaddr *serv_addr , int addrlen )

        

sockfd: socket函数返回的文件描述符 

serv_addr:是包含远端主机IP地址和端口号的指针

addrlen:用来接受 serv_addr 的结构的大小,一般为sizeof(struct sockaddr_in)

  • 编写服务器端代码:
#include<stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc,char** argv)
{
        int s_fd;
        int c_fd
        struct sockaddr_in s_addr;
        struct sockaddr_in c_addr; 

        if(argc!=3){
                printf("argc no 3\n");
                exit(-1);
        }

        s_fd=socket(AF_INET ,SOCK_STREAM ,0);
        if(s_fd==-1){
                perror("socket");
        }

        s_addr.sin_family=AF_INET;
        s_addr.sin_port=htons(atoi(argv[2]));
        s_addr.sin_addr.s_addr=inet_addr(argv[1]);


        bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));

        listen(s_fd,10);

        int len=sizeof(struct sockaddr_in);

        c_fd=accept(s_fd,(struct sockaddr *)&c_addr,&len);
        if(c_fd==-1){
            perror("reason:");
        }

        puts("connected successfully");
        printf("clientIP:%s\n",inet_ntoa(c_addr.sin_addr));

             
        return 0;
}

 服务端代码编写好后,可以在window用 telnet 测试一下是否能连接上

连接成功,并输出 window 的IP地址

  • 编写客户端的代码:
#include<stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>

int main(int argc,char** argv)
{
        int c_fd;

        if(argc!=3){
                printf("argc no 3\n");
                exit(-1);
        }

        c_fd=socket(AF_INET ,SOCK_STREAM,0);
        if(c_fd==-1){
                perror("socket");
        }

        struct sockaddr_in c_addr;
        c_addr.sin_family=AF_INET;
        c_addr.sin_port=htons(atoi(argv[2]));
        s_addr.sin_addr.s_addr=inet_addr(argv[1]);


        if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in))==-1){
                perror("connect");
        }



        return 0;
}

客户端成功连接服务器: 

客户端连接服务器后可以通过 read()和 write()或者 recv() 和 send()等进行数据传送

ssize_t read( int fd , void *buf , size_t count )
ssize_t write( int fd , const void *buf , size_t count )

fd:指定接收端或发送端套接字描述符
buf:指明一个缓冲区,该缓冲区用来存放 read 接收到的数据 或 write 发送的数据
count:指明buf的长度

ssize_t send( int sockfd , const void *buf , size_t len, int flags );
ssize_t recv( int sockfd , void *buf, size_t len , int flags );

fd:指定接收端或发送端套接字描述符
buf:指明一个缓冲区,该缓冲区用来存放 recv 接收到的数据 或 send 发送的数据
len指明buf的长度
flags:指定调用方式,一般置0

以下以read、write 为例

 服务器端:

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

int main(int argc,char** argv)
{
        int s_fd;
        int c_fd;
        char readbuf[128]={'\0'};
        struct sockaddr_in s_addr;
        struct sockaddr_in c_addr;

        if(argc !=3){
                puts("argc no 3");
        }

        s_fd=socket(AF_INET,SOCK_STREAM,0);

        s_addr.sin_family=AF_INET;
        s_addr.sin_port=htons(atoi(argv[2]));
        s_addr.sin_addr.s_addr=inet_addr(argv[1]);


        bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));

        listen(s_fd,10);

        int len=sizeof(struct sockaddr_in);
        c_fd=accept(s_fd,(struct sockaddr *)&c_addr,&len);

        puts("connected successfully");
        printf("clientIP:%s\n",inet_ntoa(c_addr.sin_addr));

        while(1){
                read(c_fd,readbuf,sizeof(readbuf));
                printf("%s\n",readbuf);
                memset(readbuf,0,sizeof(readbuf));
        }

        return 0;
}

客户端:

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

int main(int argc,char** argv)
{
        int c_fd;
        int n_write;
        char writebuf[128]={'\0'};
        struct sockaddr_in c_addr;

        if(argc!=3){
                printf("argc no 3\n");
                exit(-1);
        }

        c_fd=socket(AF_INET ,SOCK_STREAM,0);
        if(c_fd==-1){
                perror("socket");
        }

        c_addr.sin_family=AF_INET;
        c_addr.sin_port=htons(atoi(argv[2]));
        s_addr.sin_addr.s_addr=inet_addr(argv[1]);


        if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in))==-1){
                perror("connect");
        }

        while(1){
                puts("input");
                scanf("%s",writebuf);
                n_write=write(c_fd,writebuf,strlen(writebuf));
                if(n_write==-1){
                        puts("write failed");
                        exit(-1);
                }
        }

        return 0;
}

数据传送成功:

当要把接收到的数据用 printf()进行输出时不要忘了加\n 否则会输出不正常.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值