Linux多线程网络编程(一)

再次开始网络编程已经是一个学期之后了。

上个学期完成网络编程之后还没有来得及总结,最近重新开始网络编程还遇到了不少的麻烦。


直奔主题:

在服务器端实现的功能:1.通过TCP/IP协议,获取客户端发送的文件。

   2.定义了几个简单的指令,对客户端进行控制。

功能特点:能同时处理最多五个客户端的请求。

服务器端的编程:

在开启网络的时候,我们首先要约定好网络协议以及服务器端开启的端口。

 

#include <arpa/inet.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <stdlib.h>

struct sockaddr_in serv_addr; //一个包含服务器端信息的结构体

struct sockaddr_in clnt_addr; //客户端的结构体

int init_networking(int Port)

{

    int sock;

    sock=socket(PF_INET,SOCK_STREAM,0); //定义一个流式套接字

    memset(&serv_addr,0,sizeof(serv_addr)); //为结构体开辟空间

    serv_addr.sin_family=AF_INET; //定义协议

    serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); //使用本地IP地址

    serv_addr.sin_port=htons(Port); //使用的端口号

 

    if(bind(sock,(struct sockaddr*) & serv_addr,

                            sizeof(serv_addr))==-1) //绑定端口号

        perror("bind  "); //在 stdlib.h中有定义

 

    if(listen(sock,5)==-1) //在对应端口开始监听,监听的套接字最多为5

        perror("listen  ");

    return sock; //返回一个本地服务器的套接字

}

 

 

#include <pthread.h> //包含对线程函数的定义

主函数:初始化网络,对每个接入服务器的客户端开启一个线程进行相应的处理。

int main(void)

{

    int server_sock; //服务器的套接字

    server_sock=init_networking(1000); //初始化服务器套接字

    pthread_t newthread; //创建一个线程的标志

    int client_sock; //定义一个客户端套接字

    int clnt_addr_size; //定义客户端IP地址大小

    clnt_addr_size=sizeof(clnt_addr);

    while(1)

    {

        client_sock=accept(server_sock,(struct sockaddr*) &clnt_addr,&clnt_addr_size); //接受一个客户端的请求,为客户端分配一个套接字

            perror("accept");

 

        if (pthread_create(&newthread , NULL,accept_request, client_sock) != 0)

            perror("pthread_create"); //创建一个线程处理之前的客户端请求

    }

 

    close(server_sock);

    return 0;

}

 

 

处理客户端的请求:

一旦客户端连接上服务器,客户端会向服务器发送一个对应的连接模式(控制模式OR图片传输模式)

void accept_request(int client_sock)

{

int mode_select,i;

 /×     接收客户端的连接模式的选择位      ×/

recv(client_sock,&mode_select,sizeof(int),MSG_WAITALL);       

if(mode_select==1)

    {

        for(i=0;i<3;i++)

        {

            convert_picture(client_sock); //进入图像传输模式

        }

    }

    if(mode_select==2)

    {

        cmd_control(client_sock); //进入控制指令模式

    }

}

 

图片传输和控制函数在此不做详细的解释,因为它的通用性不强,主要是对文件的数据包的组装,以及传输相应的控制指令让客户端有相应的应答。

 


 

客户端的设计主要思路:

1.使用两套套接字,一套套接字用于文件传输,另一套套接字用于控制指令传输。

2.在主函数中创建一个控制线程,线程的生命周期和主函数一样,这样能够实时的控制主函数。

3.进程和线程的通讯使用全局变量的方式

特点:

使用两套套接字的好处就是能够将传输数据和控制指令隔离开,能够相互不影响,降低出错的概率。

客户端的实现:

#include <arpa/inet.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <stdio.h>

#include <stdlib.h>

int serv_sock,serv_sock2;

int init_convert(const char *IP_addr,int Port)

{

    serv_sock=socket(PF_INET,SOCK_STREAM,0); //开启套接字1

    serv_sock2=socket(PF_INET,SOCK_STREAM,0);//开启套接字2

    if(serv_sock==-1)

        perror("socket");

    memset(&serv_addr,0,sizeof(serv_addr));

    serv_addr.sin_family=AF_INET;

    serv_addr.sin_addr.s_addr=inet_addr(IP_addr);

serv_addr.sin_port=htons(Port);

/× 套接字1连接服务器 ×/

    if(connect(serv_sock,(struct sockaddr*) & serv_addr,sizeof(serv_addr))==-1)

        perror("connect1 ");

/× 套接字2连接服务器 ×/

    if(connect(serv_sock2,(struct sockaddr*) & serv_addr,sizeof(serv_addr))==-1)

        perror("connect2 ");

    int mode;

    mode=1;

    send(serv_sock,&mode,sizeof(int),MSG_WAITALL); //套接字一用于图片传输

    mode=2;

    send(serv_sock2,&mode,sizeof(int),MSG_WAITALL);//套接字二用于控制指令传输

    return 0;

}

 

主函数中开启了一个线程,直到主函数进程结束才结束。这样我们就能在程序的生命周期内对程序进行实时的控制。

pthread_t cmd_thread;

if(pthread_create(&cmd_thread , NULL,cmd_convert,NULL) != 0)

    perror("pthread_create");

这个进程用于传输控制指令,控制指令与主函数的通信方式,采用全局变量的方式。


不足:在文件传输的过程中,我的函数缺乏高可用性。在线程间的通讯方式可以改为signal的方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值