Linux网络编程——服务器与客户端

1 单连接C/S

简单实现单连接的服务器与客户端,服务器处理客户端的字符为大写返回给客户端

  • 服务器端
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <ctype.h>
#include <arpa/inet.h>
#define SERV_PORT 6666
#define SERV_IP "127.0.0.1"
int main()
{
    int lfd,cfd;
    char buf[BUFSIZ],clie_IP[BUFSIZ];
    int n;
    struct sockaddr_in serv_addr, clie_addr;
    socklen_t clie_addr_len;
    /*创建一个socket 指定IPv4协议族 TCP协议*/
    lfd = socket(AF_INET, SOCK_STREAM, 0);

    /*初始化一个地址结构 man 7 ip 查看对应信息*/
    bzero(&serv_addr, sizeof(serv_addr));           //将整个结构体清零
    serv_addr.sin_family = AF_INET;                 //选择协议族为IPv4
    serv_addr.sin_port = htons(SERV_PORT);          //绑定端口号    
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY这个宏可以自动转换为本地有效的IP
    /*绑定服务器地址结构*/
    bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));

    listen(lfd, 128);   //同一时刻允许向服务器发起链接请求的数量
    printf("wait for client connect ...\n");

    clie_addr_len = sizeof(clie_addr);/*获取客户端地址结构大小*/

    /*参数1是sfd; 参2传出参数, 参3传入传出参数, 全部是client端的参数*/
    cfd = accept(lfd, (struct sockaddr *)&clie_addr, &clie_addr_len);
    printf("client IP:%s\tport:%d\n", 
            inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr, clie_IP, sizeof(clie_IP)), 
            ntohs(clie_addr.sin_port));
    while(1){
        /*读取客户端发送数据*/
        n = read(cfd, buf, sizeof(buf));
        //小写转大写发送给客户端
        for(i=0;i<n;i++)
            buf[i] = toupper(buf[i]);
        write(cfd, buf,n);
    }
    close(lfd);
    close(cfd);
    return 0;
}
  • 客户端
client.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define SERV_IP "127.0.0.1"
#define SERV_PORT 6666
int main()
{
    int sfd,serv_addr_len,cfd;
    char buf[BUFSIZ];
    int n;

    sfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in serv_addr;//服务器IP+port
    bzero(&serv_addr, sizeof(serv_addr));//清零
    serv_addr.sin_family = AF_INET;
    inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);//IP字符串转换为网络字节序 参3:传出参数
    serv_addr.sin_port = htons(SERV_PORT);//端口号转网络字节序

    connect(sfd,(struct sockaddr*)&serv_addr, sizeof(serv_addr));
    while(1){
        fgets(buf, sizeof(buf), stdin);/*从标准输入获取数据*/
        write(sfd, buf, strlen(buf));/*将数据写给服务器*/
        len = read(sfd, buf, sizeof(buf));/*从服务器读回转换后数据*/
        write(STDOUT_FILENO, buf,len); /*写至标准输出*/
    }
    close(sfd);
    return 0;
}

2 多进程并发C/S

  • 服务器端(多进程并发)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <strings.h>
#include <ctype.h>
#define SERV_PORT 8888
void wait_child(int signo){
    while(waitpid(0,NULL,WNOHANG)>0);//子进程回收
    return ;
}
int main()
{
    pid_t pid;
    int lfd,cfd;
    struct sockaddr_in serv_addr,clie_addr;
    socklen_t clie_addr_len;
    char buf[BUFSIZ],clie_IP[BUFSIZ];
    int n,i;

    lfd = socket(AF_INET, SOCK_STREAM,0);
    bzero(&serv_addr, sizeof(serv_addr));//	清零
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    //inet_pton(AF_INET,"192.168.43.1",serv_addr.sin_addr.s_addr);
    bind(lfd,(struct sockaddr *)&serv_addr, sizeof(serv_addr));
    listen(lfd,128);

    while(1){//接活,处理新到来的连接
        clie_addr_len = sizeof(clie_addr);
        cfd = accept(lfd, (struct sockaddr *)&clie_addr, &clie_addr_len);
        printf("client IP:%s, port:%d\n",
            inet_pton(AF_INET,&clie_addr.sin_addr.s_addr, clie_IP, sizrof(clie_IP)),
            ntohs(clie_addr.sin_port) )
        pid = fork();
        if(pid<0){
            perror("fork error");
            exit();
        }else if(pid==0){   //子进程
            close(lfd); 
            break;
        }else{
            close(cfd);
            signal(SIGCHLD,wait_child);//处理僵尸进程,子进程
        }
    }
    if(pid==0){ //子进程处理连接的数据
        while(1){
            n = read(cfd,buf,sizeof(buf));
            if(n==0){   //client closed
                close(cfd);
                return 0;
            }else if(n==-1){
                perror("read error");
                exit(1);
            }else{
                for(i=0;i<n;i++)
                    buf[i] = toupper(buf[i]);
                write(cfd,buf,n);
                write(STDOUT_FILENO,buf,n);
            }
        }
    }
    return 0;
}

3 多线程并发

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <strings.h>
#include <ctype.h>

#define MAXLINE 8192
#define SERV_PORT 8000
struct s_info{
    struct sockaddr_in cliaddr;
    int connfd;
}
void *do_work(void *arg){
    int n,i;
    struct s_info *ts = (struct s_info*)arg;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];  //define INET_ADDRSTRLEN 16
    while(1){
        n = read(ts->connfd,buf,MAXLINE);
        if(n==0){
            printf("the client %d closed...\n",ts->connfd);
            break;
        }
        printf("reveived from %s at PORT %d\n",
            inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
            ntohs((*ts).cliaddr.sin_port));
        for(i=0;i<n;i++)
            buf[i] = toupper(buf[i]);
        write(STDOUT_FILENO,buf,n);
        write(ts->connfd,buf,n);
    }
    close(ts->connfd);
    return (void*)0;
}
int main()
{
    struct sockaddr_in serv_addr, clie_addr;
    socklen_t clie_addr_len;
    int listenfd,connfd;
    pthread_t tid;
    struct s_info ts[256];
    int i=0;
    
    listenfd = socket(AF_INET,SOCK_STREAM, 0);
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(SERV_PORT);
    bind(listenfd,(struct sockaddr *)&serv_addr, sizeof(serv_addr));
    listen(listenfd,128);
    printf("Accepting client connet ...\n");
    while(1){
        clie_addr_len = sizeof(clie_addr);
        connfd = accept(listenfd,(struct sockaddr *)&clie_addr, &clie_addr_len);//阻塞监听客户端请求
        ts[i].cliaddr = clie_addr;
        ts[i].connfd = connfd;
        /*达到线程最大数时,pthread_create出错处理,增加服务器稳定性 */
        pthread_create(&tid,NULL,do_work,(void*)&ts[i]);
        pthread_detach(tid);    //子线程分离,防止僵尸线程产生
        i++;//统计是第几个线程
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值