码迷,mamicode.com
首页 > 其他好文 > 详细

socket编程

时间:2019-08-02 22:57:43      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:har   int   读写文件   小端   大端   cpe   res   初始化   ems   

一。socket概念

Socket本身有“插座”的意思,在Linux环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。

既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。与管道类似的,Linux系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递。

技术图片

二。网络字节序和sockaddr

1.网络字节序

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

 

ip转换

#include <arpa/inet.h>

int inet_pton(int af, const char *src, void *dst);   

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

 

2.sockaddr数据结构

struct sockaddr_in {

    __kernel_sa_family_t sin_family;           /* Address family */    地址结构类型

    __be16 sin_port;                          /* Port number */      端口号

    struct in_addr sin_addr;                   /* Internet address */ IP地址

    /* Pad to size of `struct sockaddr‘. */

    unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -

    sizeof(unsigned short int) - sizeof(struct in_addr)];

};

struct sin_addr{

  uint32 s_addr;

}

 

三。socket通信模型

技术图片

 

四。socket主要函数

 1.socket函数

创建一个套接字,即打开网络通讯端口如果成功的话,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1。

技术图片

 

2.bind函数

bind()的作用是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号

技术图片

 

3.listen函数

 listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态

技术图片

返回值:  listen()成功返回0,失败返回-1

 

4.accept函数

三方握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。addr是一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-result argument),传入的是调用者提供的缓冲区addr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度

技术图片

 

5.connect函数

客户端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。

技术图片

 

6.客服端服务端套接字通信

服务端

//server.c
#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<strings.h>
#define SERV_PORT 6666
#define SERV_IP "127.0.0.1"
int main()
{
        int lfd,cfd;   
        lfd=socket(AF_INET,SOCK_STREAM,0);  //创建套接字 ipv4 TCP 方式
        socklen_t clie_addr_len;        //客户端长度

        struct sockaddr_in serv_addr,clie_addr;   //定义服务端和客户端sockaddr
       bzero(&serv_addr,sizeof(serv_addr));
        serv_addr.sin_family=AF_INET;   //初始化服务端sockaddr 设置ipv4
        serv_addr.sin_port=htons(SERV_PORT);  //设置 端口号
        serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); //设置ip INADDR_ANY为本地可用ip
        bind(lfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)); //绑定套接字和addr

        listen(lfd,100);  //设置客户端同时连接数

        clie_addr_len=sizeof(clie_addr);  //获得的客户端sockaddr 长度
  
        cfd=accept(lfd,(struct sockaddr*)&clie_addr,&clie_addr_len); 
//cfd为与客户端通讯的实际的文件描述符,clie_addr为传出参数,保护客户端地址信息,clie_addr_len为传入传入参数accpet之后会阻塞等待客户端connect 
        printf("client ip:%s,client port:%d\n",inet_ntop(AF_INET,&clie_addr.sin_addr.s_addr,clie_IP,sizeof(clie_IP)),ntohs(clie_addr.sin_port));

        char buf[BUFSIZ];
        int count,i;
        while(1)
        {
                count=read(cfd,buf,sizeof(buf)); //从套接字另一端读数据
                for(i=0;i<count;i++)
                {
                        buf[i]=toupper(buf[i]);  //将小写字母转换成大写字母
                }
                write(cfd,buf,count);   //将数据写入
        }
        close(cfd);  //关闭套接字
        close(lfd);  //关闭套接字

        return 0;
}    

客户端

#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<string.h>


#define SERV_IP "127.0.0.1"
#define SERV_PORT 6666
int main()
{
        int fd;  //文件描述符
        fd=socket(AF_INET,SOCK_STREAM,0);//创建套接字
        struct sockaddr_in serv_addr; //服务器地址

        memset(&serv_addr,0,sizeof(serv_addr)); //将serv_addr清0
        serv_addr.sin_family=AF_INET;  //设置服务器 ipv4
        serv_addr.sin_port=htons(SERV_PORT); //端口
        inet_pton(fd,SERV_IP,&serv_addr.sin_addr.s_addr); //ip

        connect(fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)); //连接服务器

        char buf[BUFSIZ];
        int count;
        while(1)
{
        fgets(buf,sizeof(buf),stdin);  //键盘输入
        write(fd,buf,strlen(buf));  //向套接字写数据
        count=read(fd,buf,sizeof(buf)); //从服务器读返回的数据
        write(STDOUT_FILENO,buf,count); //写到屏幕上
}
        close(fd);
        return 0;
}

  

 

 

socket编程

标签:har   int   读写文件   小端   大端   cpe   res   初始化   ems   

原文地址:https://www.cnblogs.com/sclu/p/11291457.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!