美文网首页
Linux下socket编程

Linux下socket编程

作者: 吴金君 | 来源:发表于2019-05-03 15:47 被阅读0次

套接字地址结构

\include<netinet/in.h>
struct in_addr
{
  in_addr_t s_addr; 
};
struct sockaddr_in
{
  uint8_t  sin_len;
  sa_family_t sin_family;
  in_port_t sin_port;
  struct in_addr sin_addr[8];
}

TCP

image

总结函数用法

socket函数
#include <sys/socket.h>
socket(int family,int type, int protocol)
参数:family 指明协议族,type 指数据类型,protocol 指协议
返回值:成功为非负描述符,若出错则为-1

family
type
protocol

bind函数
#include <sys/socket.h>
int bind(int sockfd,const struct sockaddr * myaddr, socklen_t addrlen)
参数:sockfd指socket套接字描述符,myaddr指向需要绑定的网络地址结构,addrlen是网络地址结构的长度
返回值:成功返回0,出错返回-1

listen函数
#include <sys/socket.h>
int listen(int sockfd,int backlog)
输入参数:sockfd是socket套接字描述符,backlog可以理解为连接队列容量大小(已连接+未连接)
返回值:成功返回0,出错返回-1

accept函数
#include <sys/socket.h>
int accept(int sockfd, const struct sockaddr * clientaddr, socklen_t addrlen)
输入参数:sockfd是socket套接字描述符,clientaddr指向客户的网络地址结构,addrlen是网络地址结构的大小。
返回值:成功返回非负描述符,出错返回-1

connect函数
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr * servaddr, socklen_t addrlen)
TCP客户端用connect函数发起与服务器的连接
参数:sockfd指socket函数返回的套接字描述符,*servaddr是指向套接字结构的指针,addrlen是套接字结构的大小
返回值:成功返回0,出错返回-1
sockfd是客户端套接字描述符
servaddr套接字结构必须含有服务器IP和端口

send函数
ssize_t send(int sockfd, const char *buf, size_t len, int flags );
参数:sockfd套接字(已连接套接字),buf是发送缓存区,len是缓存区长度,
返回值:copy的字节数

recv函数
ssize_t recv(int sockfd, char *buf, size_t len, int flags)
参数:参数:sockfd套接字(已连接套接字),buf是接收缓存区,len是缓存区长度。
返回值:copy的字节数

close函数
close(int sockfd)将套接字标记为关闭
参数:sockfd指socket函数返回的套接字描述符

read函数
#include<unistd.h>
sszie_t read(int fd, void* buf, size_t nbyte)
参数:fd文件描述符,nbyte
返回值:读到的字节数;若到文件尾部,返回0;若出错返回-1

write函数
#include<unistd.h>
sszie_t write(int fd, void* buf, size_t nbyte)
参数:fd文件描述符,buf待写入的缓存
返回值:若成功,返回写入的字节数;若出错返回-1

socket(), connect(), accept()三个函数之间的关系
  1. socket函数创建的监听套接字(listening socket)描述符,随后用作bind和listen的第一个参数
  2. accept函数返回值为已连接套接字(connected socket)描述符
  3. 一个服务器通常仅仅创建一个监听套接字,在服务器生命周期中一直存在;
  4. 内核为每个已连接客户端创建一个已连接套接字

服务端处理流程:

  1. 调用socket函数,建立套接字描述符
  2. 创建网络地址数据结构,指定要监听的IP和PORT
  3. 调用bind函数,将套接字描述符合万罗地址数据结构绑定
  4. 调用listen函数,将套接字描述符转为监听套接字,表示该描述符是用于从指定地址和端口接收连接的
  5. 阻塞等待,调用accept函数来获取连接
  6. 得到连接后使用read和write函数往描述符中读写数据
  7. 完成后调用close关闭套接字描述符

客户端处理流程

  1. 调用socket函数,创建套接字描述符
  2. 创建网络地址结构,指定要连接的服务端IP和PORT
  3. 调用connect函数连接服务器
  4. 连接成功后调用read和write函数读写数据
  5. 完成后调用close关闭描述符

server代码

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <iostream>
#define PORT 7000
#define QUEUE 20

int main()
{
    fd_set rfds;
    struct timeval tv;
    int retval,maxfd;
    //创建socket
    int listener =socket(AF_INET,SOCK_STREAM,0);//ipv4,stream data,TCP
    struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(PORT);
    server_sockaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    //bind
    if(bind(listener,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))<0);
    {
        perror("bind error");
        exit(1);
    }
    //listen
    if(listen(listener,QUEUE)<0)
    {
        perror("listen");
        exit(1);
    }
    //connect
    struct sockaddr_in client_addr;
    socklen_t length= sizeof(client_addr);
    int conn=accept(listener,(struct sockaddr *)&client_addr,&length);
    if(conn<0)
    {
        perror("connect");
        exit(1);
    }
    while(1)
    {
        /*把可读文件描述符的集合清空*/
        FD_ZERO(&rfds);
        /*把标准输入的文件描述符加入到集合中*/
        FD_SET(0, &rfds);
        maxfd = 0;
        /*把当前连接的文件描述符加入到集合中*/
        FD_SET(conn, &rfds);
        /*找出文件描述符集合中最大的文件描述符*/
        if(maxfd<conn)
        {
            maxfd=conn;
        }
        /*设置超时时间*/
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
        if(retval == -1){
            printf("select出错,客户端程序退出\n");
            break;
        }else if(retval == 0){
            printf("服务端没有任何输入信息,并且客户端也没有信息到来,waiting...\n");
            continue;
        }else{
            /*客户端发来了消息*/
            if(FD_ISSET(conn,&rfds))
            {
                char buffer[1024];
                memset(buffer, 0,sizeof(buffer));
                int len = recv(conn,buffer,sizeof(buffer),0);
                if(strcmp(buffer,"exit\n")==0)break;
                printf("%s",buffer);
                //send(conn,buffer,len,0);
                
            }
            /*用户输入信息了,开始处理信息并发送*/
            if(FD_ISSET(0,&rfds))
            {
                char buf[1024];
                fgets(buf,sizeof(buf),stdin);
                send(conn,buf,sizeof(buf),0);
            }
        }
    }
    close(conn);
    close(listener);
    return 0;
}

client代码

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

#define MYPORT  7000
#define BUFFER_SIZE 1024

int main()
{
    int sock_client;
    fd_set rfds;
    struct timeval tv;
    int retval, maxfd;
    
    //定义 sockfd
    sock_client = socket(AF_INET,SOCK_STREAM,0);
    //定义 socketaddr_in
    struct sockaddr_in serveraddr;
    memset(&serveraddr,0,sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(MYPORT);
    serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");//server ip
    
    while(connect(sock_client,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0)
    {
        perror("connect");
        exit(1);
    }
    
    while(1)
    {
        /*把可读文件描述符的集合清空*/
        FD_ZERO(&rfds);
        /*把标准输入的文件描述符加入到集合中*/
        FD_SET(0, &rfds);
        maxfd = 0;
        /*把当前连接的文件描述符加入到集合中*/
        FD_SET(sock_client, &rfds);
        /*找出文件描述符集合中最大的文件描述符*/
        if(maxfd < sock_client)
            maxfd = sock_client;
        /*设置超时时间*/
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        /*等待聊天*/
        retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
        if(retval == -1){
            printf("select出错,客户端程序退出\n");
            break;
        }else if(retval == 0){
            printf("客户端没有任何输入信息,并且服务器也没有信息到来,waiting...\n");
            continue;
        }else{
            /*服务器发来了消息*/
            if(FD_ISSET(sock_client,&rfds))
            {
                char recvbuf[BUFFER_SIZE];
                int len;
                len = recv(sock_client,recvbuf,sizeof(recvbuf),0);
                printf("%s",recvbuf);
                memset(recvbuf,0,sizeof(recvbuf));
            }
            if(FD_ISSET(0,&rfds))
            {
                char sendbuf[BUFFER_SIZE];
                fgets(sendbuf,sizeof(sendbuf),stdin);
                send(sock_client,sendbuf,strlen(sendbuf),0);
                memset(sendbuf,0,sizeof(sendbuf));
            }
        }
    }
    close(sock_client);
    return 0;
}

https://blog.csdn.net/chenchukun/article/details/78991215

相关文章

  • Linux下的Socket编程(主要包括TCP部分)

    Linux下的Socket编程(主要包括TCP部分) 转载麻烦注明原文地址本文是Linux下基本的Socket编程...

  • 网络编程

    Linux Socket编程(不限Linux) C/C++ socket编程教程:1天玩转socket通信技术 一...

  • Linux下socket编程

    套接字地址结构 TCP 总结函数用法 socket函数#include socket(int family,in...

  • Linux网络编程篇之ICMP协议分析及ping程序实现

    Linux网络编程系列: Linux网络编程篇之Socket编程预备知识 Linux网络编程篇之TCP协议分析及聊...

  • Linux下的socket编程

    server.cpp 是服务器端代码,client.cpp 是客户端代码,要实现的功能是:客户端从服务器读取一个字...

  • linux下Socket编程(一)

    简介 Socket理论 Socket工作流程 核心函数讲解 服务的如何获取客户端的信息 字符串ip和网络二进制的转...

  • linux下socket编程实例

    一、基本socket函数Linux系统是通过提供套接字(socket)来进行网络编程的。网络的socket数据传输...

  • Linux下的socket编程

    server.cpp 是服务器端代码,client.cpp 是客户端代码,要实现的功能是:客户端从服务器读取一个字...

  • TCP socket 编程

    TCP socket 编程 讲一下 socket 编程 步骤 使用 socket 模块 建立 TCP socket...

  • OpenResty搭建高性能服务端

    Socket编程 Linux Socket编程领域为了处理大量连接请求场景,需要使用非阻塞I/O和复用,selec...

网友评论

      本文标题:Linux下socket编程

      本文链接:https://www.haomeiwen.com/subject/pdtxoftx.html