c语言socket ipv4服务端

编程入门 行业动态 更新时间:2024-10-27 14:23:56

c语言socket ipv4<a href=https://www.elefans.com/category/jswz/34/1769467.html style=服务端"/>

c语言socket ipv4服务端

socket ipv4服务端
1)创建socket fd
listen_st = socket(AF_INET,SOCK_STREAM,0);
2)初始化server端ip以及端口的信息
    struct sockaddr_in sockaddr;
    setsockopt(listen_st,SOL_SOCKET,SO_REUSEADDR,&ON,sizeof(on);    //设置ip可以重用
    sockaddr.sin_port = htons(port);
    sockaddr.sin_family = AF_INET;
    sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);//任何ip都可以连接
3)把sockaddr_in 绑定到socket_fd上
    bind(listen_st,(struct sockaddr *)&sockaddr,sizeof(sockaddr)
4)监听端口,等待连接
    listen(listen_st,5)  //监听最多5个连接
5)阻塞接收,获取外部客户端连接过来的文件id  accept_st
    struct sockaddr_in accept_sockaddr;//用于存储连接过来的socket信息
    socklen_t addrlen = sizeof(accept_sockaddr);
    accept_st = (listen_st,(struct sockaddr*)&accept_sockaddr,&addrlen);
    在已建立连接的listen_st上监听,给accept_sockaddr
6)建立发送线程
    phread_create(&send_thrd,NULL,thread_send,&accept_st);
    pthread_detach(send_thrd);子线程与主线程分离,自己独立执行
7)建立接收线程
    struct pthread_socket{
        int socket_d;
        pthread_t thrd;
    };
    pthread_socket ps;
    ps.socket_d = accept_st;  //接收文件id,linux一切皆为文件
    ps.pthread_t thrd;        //为什么给了发送线程,因为接收完毕后, 需要发送给客户
    pthread_create(&recv_thrd,NULL,thread_recv,&ps);
    pthread_detach(recv_thrd); 接收线程独立开来
   

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#define MXCONN 2
#define ERRORCODE -1
#define BUFFSIZE 1024
int count_connect = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//
struct pthread_socket{
    int socket_d;
    pthread_t thrd;
};

static void *thread_send(void *arg){
    char buf[BUFFSIZE];
    int sd = *(int *)arg;     //this is accept_st
    memset(buf,0,sizeof(buf));
    strcpy(buf,"hello,welcome to you !\n");
    if(send(sd,buf,strlen(buf),0)==-1){
        printf("send error:%s \n",strerror(errno));
        return NULL;
    }
    while(1){
        memset(buf,0,sizeof(buf));
        read(STDIN_FILENO,buf,sizeof(buf));    //键盘输入的信息 阻塞在这儿
        if(send(sd,buf,strlen(buf),0)==-1){
            printf("send error:%s \n",strerror(errno));
            break;
        }
    }
    return NULL;
}

static void* thread_recv(void *arg){
    char buf[BUFFSIZE];
    struct pthread_socket *pt = (struct pthread_socket *)arg;
    int sd = pt->socket_d;          //链接过来的accept_st
    pthread_t thrd = pt->thrd;      //发送线程
    while(1){
        memset(buf,0,sizeof(buf));
        int rv = recv(sd,buf,sizeof(buf),0); //阻塞
        if(rv<0){
            printf("recv error:%s\n",strerror(errno));
            break;
        }
        if(rv ==0){  //这种情况说明client已经关闭socket连接
            break;
        }
        printf("%s",buf);//输出接收内容
    }
    pthread_cancel(thrd);        //取消了发送线程
    pthread_mutex_lock(&mutex);
    count_connect--;
    pthread_mutex_unlock(&mutex);
    close(sd);
    return NULL;
}

static int create_listen(int port){
    int listen_st;
    struct sockaddr_in sockaddr; //定义IP地址结构
    int on = 1;
    listen_st = socket(AF_INET,SOCK_STREAM,0);  //初始化socket(TCP)
    if(listen_st == -1){
        printf("socket create error:%s \n",strerror(errno));
        return ERRORCODE;
    }
    if(setsockopt(listen_st,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))==-1){ //设置IP地址可重用
        printf("setsockopt error:%s \n",strerror(errno));
        return ERRORCODE;
    }
    sockaddr.sin_port = htons(port);   //指定一个端口号并将hosts字节型转化成int型(大端或者小端)
    sockaddr.sin_family = AF_INET;     //设置为tcp/ip模式
    sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);  //服务端等待别人来连接,不需要找谁的ip
    //这里写一个常量INADDR_ANY表示server上所有IP,这个server可能有多个ip地址,因为可能有多网卡
    if(bind(listen_st,(struct sockaddr *)&sockaddr,sizeof(sockaddr))==-1){
        printf("bind error:%s \n",strerror(errno));
        return ERRORCODE;
    }

    if(listen(listen_st,5)==-1){
        printf("listen error:%s \n",strerror(errno));
        return ERRORCODE;
    }
    return listen_st;
}

int accept_socket(int listen_st){
    int accept_st;
    struct sockaddr_in accept_sockaddr;
    socklen_t addrlen = sizeof(accept_sockaddr);
    memset(&accept_sockaddr,0,addrlen);
    accept_st = accept(listen_st,(struct sockaddr *)&accept_sockaddr,&addrlen);
    //accept 会阻塞知道客户端链接过来 服务端这个socket只负责listen 是不是有客户端连接过来
    //是通过acept返回socket通信的
    if(accept_st == -1){
        printf("accept error:%s \n",strerror(errno));
        return ERRORCODE;
    }
    printf("accept ip;%s \n",inet_ntoa(accept_sockaddr.sin_addr));
    return accept_st;
}

int run_sersver(int port){
    int listen_st = create_listen(port);
    pthread_t send_thrd,recv_thrd;
    struct pthread_socket ps;
    int accept_st;
    if(listen_st==-1){
        return ERRORCODE;
    }
    printf("server start \n");
    while(1){
        accept_st = accept_socket(listen_st);
        if(accept_st == -1){
            return ERRORCODE;
        }
        if(count_connect >=_PC_MAX_CANON){
            printf("connet have already be full! \n");
            close(accept_st);
            continue;
        }
        pthread_mutex_lock(&mutex);
        count_connect++;
        pthread_mutex_unlock(&mutex);
        if(pthread_create(&send_thrd,NULL,thread_send,&accept_st)!=0){  //创建发送信息线程
            printf("create thrad error:%s \n",strerror(errno));
            break;
        }
        pthread_detach(send_thrd);                  //设置线程可分离,这样的话主线程就不用Join
        ps.socket_d = accept_st;
        ps.thrd = send_thrd;
        if(pthread_create(&recv_thrd,NULL,thread_recv,&ps)!=0){
            printf("create thread error %s\n",strerror(errno));
            break;
        }
        pthread_detach(recv_thrd);                //独立与主线程操作
    }
    close(accept_st);
    close(listen_st);
    return 0;
}

int main(int argc,char * argv[]){
    if(argc<2){
        printf("Usage:port ,example:8080 \n");
        return -1;
    }
    int port = atoi(argv[1]);
    if(port==0){
        printf("port error \n");
    }else{
        run_sersver(port);
    }
    return 0;
}

参考:

更多推荐

c语言socket ipv4服务端

本文发布于:2023-11-16 08:41:54,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1615336.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:服务端   语言   socket

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!