Socket网络编程(TCP/IP)实现服务器/客户端通信。

一.前言

回顾之前进程间通信(无名管道,有名管道,消息队列,共享内存,信号,信号量),都是在同一主机由内核来完成的通信。

那不同主机间该怎么通信呢?

可以使用Socket编程来实现。

Socket编程可以通过网络来实现实现不同主机之间的通讯。

二.Socket编程的网络模型如下。

1.创建socket

创建通讯套接字

int socket(int domain, int type, int protocol);
//参数一:是通信时候用的协议族
// AF_UNIX, AF_LOCAL      用于本地进程/线程的网络通信
//AF_INET                 用于IPV4的网络通信
//AF_INET6                用于IPV6的网络通信
//参数二:为sockt的类型
//SOCK_STREAM             流水式socket,对应的是TCP
//SOCK_DGRAM              数据报式socket 对应的是UDP
//参数三:通常填零

3.绑定socket/端口号

绑定IP地址端口号等。

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//参数一:为创建socket返回的标识符
//参数二:为一个struct sockaddr *addr的指针结构体,里面包含了,IP地址和端口号,网络编程是一般使用的是struct sockaddr_in类型的。
// struct sockaddr_in 
//   {       
//       u_short sin_family;      // 地址族, AF_INET   
//       u_short sin_port;        // 端口号 
//      struct in_addr sin_addr; // IPV4地址      
//   char sin_zero[8];        // 8 bytes unused,作为填充
//    }; 
//如果使用了struct sockaddr_in类型的,左后一定要强转成struct sockaddr *addr类型的。
//参数三:为大小,sizeof

4.监听端口号

函数原型如下

 int listen(int sockfd, int backlog);
//参数一:为创建socket返回的文件描述符
//参数e二:为能

5.接受客户端的连接请求

程序运行后服务器会一直阻塞在这 等待客户端发送连接请求。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//参数一:为创建socket返回的文件描述符
//参数二:struct sockaddr类型的指针,用来存放端口号和IP地址
//参数三:为大小sizeof

6.请求服务器连接(客户端)

向服务器发送连接请求。

 int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//参数一:为创建socket返回的文件描述符
//参数二:struct sockaddr类型的指针,用来存放端口号和IP地址
//参数三:为结构体大小

7.读取/写入

连接成功后开始信息的交互,可以使用循环,让交互不退出去

 ssize_t read(int fd, void *buf, size_t count);
//参数一:文件描述符
//参数二:缓冲区
//参数san:读取的大小
ssize_t write(int fd, const void *buf, size_t count);
//参数与read出不多

8.关闭文件

通讯完毕,关闭文件

int close(int fd);
//参数:你要关闭哪个文件就写哪个文件的文件描述符

三.示例代码

1.server.c

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

int main(int argc,char *argv[])
{
    struct sockaddr_in addr;
    struct sockaddr_in addr2;
    memset(&addr,0,sizeof(struct sockaddr_in));
    memset(&addr2,0,sizeof(struct sockaddr_in));
    char *readbuf = (char *)malloc(sizeof(struct sockaddr_in)*10);
    char mas[128] ={0};
    int cockfd;
    int sockfd;
    int nread;
 
    if(argc != 3)//判断输入的参数是否等于3
    {
        printf("param not good\n");
        exit(-1);
    }
    
    
    if(sockfd = socket(AF_INET,SOCK_STREAM,0) == -1)//创建Socket,使用IPV4,TCP类型
    {
        printf("creat socket faild\n");
    }

    
    addr.sin_family = AF_INET;      // 地址族, AF_INET,2 bytes    
    addr.sin_port = htons(atoi(argv[2]));     // 端口,2 bytes        
    inet_aton(argv[1],&addr.sin_addr);//使用inet_aton函数将IP地址转换为网络序列。
    bind(sockfd,(struct sockaddr*)&addr,sizeof(sockaddr_in));

    listen(sockfd,10);//监听
    while(1)
    {
        //尝试连接
         cockfd = accept(sockfd,(struct sockaddr*)&addr2,sizeof(sockaddr_in));
         if(cockfd == -1)
         {
            perror("why");//失败打印原因。
         }
         printf("get conset :  %s\n",inet_nota(addr2.sin_addr));//打印连接成功的IP地址

        //创建进程,让同时维护,读和写
        if(fork() == 0)
        {
            while(1)
            {
                memset(readbuf,0,malloc_usable_size(readbuf))//每次通讯完成,内容置为0
                nread = read(cockfd,readbuf,malloc_usable_size(readbuf));//读取信息
                printf(" get message : %s\n",readbuf);//输出读取的内容
            }

            if(fork() == 0)子进程在创建一个子进程让同时运行读和写
            {
                while(1)
                {
                    memset(msg,0,sizeof(msg));//每次运行前把数组初始化
                    printf("please input\n");
                    gets(msg);//获取信息       
                    write(cockfd,msg,strlen(msg));写入信息
                }
            }
         }
    }
    return 0;   
}

示例代码

2.client.c

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

int main(int argc,char *argv[])
{
    struct sockaddr_in addr;
    memset(&addr,0,sizeof(struct sockaddr_in));
    char *readbuf = (char *)malloc(sizeof(struct sockaddr_in)*10);
    char mas[128] ={0};
    int cockfd;
    int sockfd;
    int nread;
 
    if(argc != 3)
    {
        printf("param not good\n");
        exit(-1);
    }
    
    
    ifcockfd = socket(AF_INET,SOCK_STREAM,0) == -1)
    {
        printf("creat socket faild\n");
    }

    
    addr.sin_family = AF_INET;      // 地址族, AF_INET,2 bytes    
    addr.sin_port = htons(atoi(argv[2]));     // 端口,2 bytes        
    inet_aton(argv[1],&addr.sin_addr);//使用inet_aton函数将IP地址转换为网络序列。
   
    connect(cockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr));//请求连接
    while(1)/
    {   
        if(fork() == 0)//创建进程,同时维护读写
        {
            while(1)
            {
                memset(readbuf,0,malloc_usable_size(readbuf))
                nread = read(cockfd,readbuf,malloc_usable_size(readbuf));//读取内容
                printf(" get message : %s\n",readbuf);//打印读取到的内容
            }

            if(fork() == 0)
            {
                while(1)
                {
                    memset(msg,0,sizeof(msg));
                    printf("please input\n");
                    gets(msg);    //获取信息   
                    write(cockfd,msg,strlen(msg));//写入信息
                }
            }
         }
    }
    return 0;   
}

以上就是我这段时间以来对网络编程的学习和理解,顺便记录一下,希望对你们会有所帮助,如果有不对的地方,欢迎大家来指导,谢谢

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

走下去-别回头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值