Linux下socket编程

套接字地址结构

\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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 简介 Socket理论 Socket工作流程 核心函数讲解 服务的如何获取客户端的信息 字符串ip和网络二进制的转...
    第八区阅读 3,430评论 0 4
  • 一、基本socket函数Linux系统是通过提供套接字(socket)来进行网络编程的。网络的socket数据传输...
    WB莫遥燚阅读 1,432评论 0 0
  • 网络模型 物理层 物理层表示的是比特流传输,通常包括串口/COM口、并行/LPT口、USB、网线接口、电话线接口;...
    秋风弄影阅读 666评论 0 2
  • 第一章 TCP/IP简介 基本的C/S服务模型 网络编程是指编写的网络通信程序可以与网络上的其他程序进行通信。 T...
    Waldo_cuit阅读 1,886评论 0 6
  • 坐了一天的车,真真难受。没有直达,还得转站,偏偏车还晚点。从早上好早,家里送我到公交车站,到最后到达新乡,坐了一天...
    李晓珊_三月阅读 165评论 0 0