Linux网络编程 服务器socket、bind、listen、aceept、read、write、客户端socket、client、write、read、注意端口htons和ip inet_aton

TCP/UDP对比

1. TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前       不需  要建立连接

2.  TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付

3.  TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的 UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)

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

5.  TCP首部开销20字节;UDP的首部开销小,只有8个字节

6.  TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

字节序转换(网络中采用大端排序)


不同类型的 CPU 对变量的字节存储顺序可能不同:有的系统是高位在前,低位在后,而有的系统是低位在前,高位在后,而网络传输的数据顺序是一定要统一的。所以当内部字节存储顺序和网络字节顺序不同时,就一定要进行转换.网络字节顺序采用big endian排序方式.
 

#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);
 
h表示host,n表示network,l表示32位长整数,s表示16位短整数。例如htonl表示将32位的长整数从主机字节
 
序转换为网络字节序,例如将IP地址转换后准备发送。如果主机是小端字节序,这些函数将参数做相应的大小端转
 
换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回
 
htons
    把unsigned short类型从主机序转换到网络序
htonl
    把unsigned long类型从主机序转换到网络序
ntohs
    把unsigned short类型从网络序转换到主机序
ntohl
    把unsigned long类型从网络序转换到主机序

传输模型

 服务器:
1. 创建一个socket,用函数socket()
2. 绑定IP地址、端口等信息到socket上,用函数bind()
3.设置允许的最大连接数,用函数listen()
4.接收客户端上来的连接,用函数accept()
5.收发数据,用函数send()和recv(),或者read()和write()
6.关闭网络连接


客户端:
1.创建一个socket,用函数socket()
2.设置要连接的对方的IP地址和端口等属性
3.连接服务器,用函数connect()
4.收发数据,用函数send()和recv(),或者     read()和write()
5.关闭网络连接
6.函数


SOCKET

bind();细节配置

 2)ip地址点分制和数字转换
IP地址通常由数字加点(192.168.0.1)的形式表示,而在struct in_addr中使用的是IP地址是由32位的整数表示的,为了转换我们可以使用下面两个函数:
 int inet_aton(const char *cp,struct in_addr *inp)表示将a.b.c.d形式的IP转换为32位的IP,
 inp指针里面。char *inet_ntoa(struct in_addr in) //是将32位IP转换为a.b.c.d的格式

 listen()

 accept()

 write()、read()、send()、recv()

 

 connect()

//服务器
//1socket说我要网络、2bind约定协议ip端口号、3listen监听等你来噢
//4accept连接判断三次握手成功返回fd 并把发送端得数据存放在c_ddr里面 打印ip
//5双方 读 写数据 
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>

//struct sockaddr_in {
//  __kernel_sa_family_t  sin_family;     /* Address family               */
//  __be16                sin_port;       /* Port number                  */
//  struct in_addr        sin_addr;       /* Internet address             */
//}
int main()
{

        int acceptLne = sizeof(struct sockaddr_in); //accept第三个参数大小
        int n_read;    
        char readBuf[128];//用于接收客户端数据
        char *writeBuf = "this is server send!!\n";//服务器发送数据
        int n_write;
        struct sockaddr_in s_addr;//结构体中存放服务器 协议 端口 ip
        struct sockaddr_in c_addr;//结构体中存放客户端 协议 端口 ip
        memset(&s_addr,0,sizeof(struct sockaddr_in));       //void *memset(void *s, int c, size_t n);//清空防止第二次 乱码
        memset(&c_addr,0,sizeof(struct sockaddr_in));       //void *memset(void *s, int c, size_t n);


//socket       int socket(int domain, int type, int protocol);
        int s_fd = socket(AF_INET,SOCK_STREAM,0);// 1 我要网络、ipv4、tcp、自动配置
        if(s_fd == -1){
                printf("scket failer!!\n");
                perror("why");
        }

//bind       int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(5555);
        inet_aton("192.168.1.8",&s_addr.sin_addr);       //int inet_aton(const char *cp, struct in_addr *inp);
        //  2 bind 存放socket的fd,强转addr*到addr_in*类型---放协议族、端口htons、
        // inet_aton()将ip阿斯克码 转换成网络字节序
        int bind_fd = bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
        if(bind_fd == -1){
                printf("bind failer!!\n");
                perror("why");
        }

//listen       int listen(int sockfd, int backlog);
        listen(s_fd,10);    // 3  监听fd 监听个数

        //accept 连接会判断三次握手 返回值存放在新的c_fd里面
        //s_fd,第二个参数是存放客户端的信息 协议族IPV4、端口,ip这些,第三个计算该长度
//accept       int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
        int c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&acceptLne);
        if(c_fd == -1){
                printf("accept failer!!\n");
        }
        printf("ip:%s\n",inet_ntoa(c_addr.sin_addr));//       char *inet_ntoa(struct in_addr in);              //把网络格式转换成计算机识别的阿斯克吗

// 4 读取客户端发过来的内容
//read       ssize_t read(int fd, void *buf, size_t count);
        n_read = read(c_fd,readBuf,128);
        printf("read:%d  %s\n",n_read,readBuf);

// 向客户端发送内容
//write       ssize_t write(int fd, const void *buf, size_t count);
        write(c_fd,writeBuf,strlen(writeBuf));//不能用sizeof 计算的是指针的大小

        return 0;
}
//客户端 
// socket 与服务器配置一样
//accept 和bind配置差不多 连接上后 一个发一个收
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
//struct sockaddr_in {
//  __kernel_sa_family_t  sin_family;     /* Address family               */
//  __be16                sin_port;       /* Port number                  */
//  struct in_addr        sin_addr;       /* Internet address             */
//}
int main()
{
        char *writeBuf = "connect send!\n";//客户端发送数据 服务器收
        int n_read;
        char readBuf[128];                //用于接收服务器发的数据
        struct sockaddr_in c_addr;        //定义这样一个结构体存放 协议族ipc4 端口号 ip
        memset(&c_addr,0,sizeof(struct sockaddr_in));//清空结构体里面的东西方便下次连接

//socket       int socket(int domain, int type, int protocol);
        int c_fd = socket(AF_INET,SOCK_STREAM,0);// 1 socket 我要和服务器一样的网络ipv4 tcp
        if(c_fd == -1){
                printf("scket failer!!\n");
                perror("why");
        }

//       int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
        c_addr.sin_family = AF_INET;
        c_addr.sin_port = htons(7555);
        inet_aton("192.168.1.8",&c_addr.sin_addr);       //int inet_aton(const char *cp, struct in_addr *inp);
        int connect_fd = connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in));    // 2 连接网络connet socket-fd 结构体强转addr类型、计算这个结构体大小
        if(connect_fd == -1){
                printf("connect failer!!\n");
                perror("why");
        }
// 3 往服务器发内容--》服务器收到打印---》服务器往客户端发内容---》客户端收到打印
//write       ssize_t write(int fd, const void *buf, size_t count);
        write(c_fd,writeBuf,strlen(writeBuf));
        printf("kehuduan write:%s\n",writeBuf);
// 4 读取服务器的内容
//read       ssize_t read(int fd, void *buf, size_t count);

        n_read = read(c_fd,readBuf,128);
        if(n_read ==- 1){
                printf("read error!!\n");
        }
        else {
                printf("read:%d  %s\n",n_read,readBuf);
        }
        return 0;
}

服务器与多个客户端通信

服务器端

//服务器端    创建多个子进程与多个客户端通信   gets(writeBuf)用法
//父亲门口接待  儿子不断读取  孙子不断写内容
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>

//       int socket(int domain, int type, int protocol);
//       int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//       int inet_aton(const char *cp, struct in_addr *inp);
//       int listen(int sockfd, int backlog);
//       int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);


//struct sockaddr_in {
//  __kernel_sa_family_t  sin_family;     /* Address family               */
//  __be16                sin_port;       /* Port number                  */
//  struct in_addr        sin_addr;       /* Internet address             */
//       ssize_t read(int fd, void *buf, size_t count);

int main(int argc,char **argv)    //通过main传入ip地址和端口号
{
        int s_fd;
        int c_fd;

        int bind_fd;
        int cLen = sizeof(struct sockaddr_in);

        int n_read;
        char readBuf[128] = {0};
        char writeBuf[128] = {0};

        struct sockaddr_in s_addr;
        struct sockaddr_in c_addr;
        memset(&s_addr,0,sizeof(struct sockaddr_in));
        memset(&c_addr,0,sizeof(struct sockaddr_in));

        if(argc != 3){    //判断传入参数是不是三个
                perror("argc error");
        }

        s_fd = socket(AF_INET,SOCK_STREAM,0);//  1 创建网络 返回套接字
        if(s_fd == -1){
                perror("socket");
                exit(-1);
        }

        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(atoi(argv[2]));//asscm转换成整型数 再把主机转换成网络短字符
        inet_aton(argv[1],&s_addr.sin_addr); //把字符串转换成网络字节序
        // 2 绑定套接字 绑定ipv4 ip(强转类型) 端口号
        bind_fd = bind(s_fd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr_in));
        if(bind_fd == -1){
                perror("bind");
                exit(-1);
        }

        listen(s_fd,10);    // 3 最大监听网络个数

        while(1){           //  4 来一个连接一个 不断等待连接---父亲
                c_fd = accept(s_fd,(struct sockaddr*)&c_addr,&cLen);
                if(c_fd == -1){
                        perror("accept");
                }
                else{
                        printf("IP:%s\n",inet_ntoa(c_addr.sin_addr));
                }

                if(fork() == 0){    //创建子进程 while1 不断读取

                        if(fork() == 0){
                                while(1){ // 6 再创建一个子进程  不断输入
                                    //也可定义一个mark 用sprintf                                                    
                                    //sprintf(writeBuf,"server --%d---cilent\n",mark);
                                    //write(c_fd,writeBuf,sizeof(writeBuf));
                                        memset(writeBuf,0,sizeof(writeBuf));//清空
                                        printf("input:  ");                 //提醒输入
                                        gets(writeBuf); //输入 输入的值存放再writeBuf数组中
                                        write(c_fd,writeBuf,sizeof(writeBuf));//写
                                }
                        }
                        while(1){    // 5 不断等待读取 每次都先清空readBuf里面的值
                                memset(readBuf,0,sizeof(readBuf));            
                                //先清空--程序先执行到这句再读取内容
                                n_read = read(c_fd,readBuf,128);//等待读取内容
                                if(n_read == -1){
                                        perror("read");
                                }
                                else{
                                        printf("sercer rcv:%d  %s\n",n_read,readBuf);
                                }
                        }

                }
        }

        return 0;
}
   

客户端

//通过socket 和c_addr配置和服务器连接

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

//       int socket(int domain, int type, int protocol);
//       int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//       int inet_aton(const char *cp, struct in_addr *inp);


//struct sockaddr_in {
//  __kernel_sa_family_t  sin_family;     /* Address family               */
//  __be16                sin_port;       /* Port number                  */
//  struct in_addr        sin_addr;       /* Internet address             */

int main(int argc,char **argv)//传入ip 和端口
{
        int c_fd;
        int connect_fd;

        char writeBuf[128] = {0};
        char readBuf[128] = {0};
        int n_read;

        struct sockaddr_in c_addr;
        memset(&c_addr,0,sizeof(struct sockaddr_in));

        if(argc != 3){
                perror("argc error");
        }

        c_fd = socket(AF_INET,SOCK_STREAM,0); // 1 创建网络返回套接字 ipv4 tcp 默认属性
        if(c_fd == -1){
                perror("socket");
                exit(-1);
        }

        c_addr.sin_family = AF_INET;
        c_addr.sin_port = htons(atoi(argv[2]));//字符串转整型 主机端口转网络短字节序
        inet_aton(argv[1],&c_addr.sin_addr);//inet assica转网络字节序
        connect_fd = connect(c_fd,(struct sockaddr*)&c_addr,sizeof(struct sockaddr_in));
        // 2 connect连接网络
        if(connect_fd == -1){
                perror("connect");
        }

        while(1){ //连接上后不断等待读取 并创建子进程写入数据

                if(fork() == 0){//创建子进程来发送
                        while(1){
                                memset(writeBuf,0,sizeof(writeBuf));//先清空
                                printf("input:  ");    //提醒输入
                                gets(writeBuf);// 把输入的字符串放入到writeBuf中
                                write(c_fd,writeBuf,sizeof(writeBuf));// 4 发送内容
                                printf("\n");
                        }
                }
                memset(readBuf,0,sizeof(readBuf));//先清空
                n_read = read(c_fd,readBuf,128);    // 3 等待读取
                if(n_read == -1){
                        perror("read");
                }
                else{
                        printf("client rcv:%d %s\n",n_read,readBuf);
                }
        }
        return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值