您的位置:首页 > 其它

Day34、UDP客户服务器通信、多线程

2016-09-18 21:21 162 查看
一、            将多进程和网络通讯结合

用多进程实现为多个客户服务的例子

在服务器为每个客户创建一个进程,这个进程负责和客户的通讯

fork()

子进程负责和客户端的通讯,父进程负责监听

二、            基于UDP编程

TCP提供面向连接的服务,保证数据传输的可靠性、传输数据的有序性、流量控制、全双工  

主要用于传输文件   效率低

UDP提供不面向连接的服务,不提供客户机与服务器的连接

步保证数据传输的可靠性  也是全双工

主要用于传输图片和视频   效率高

a) 基于UDP实现服务器端

第一步:创建socket

第二步:bind将fd和目标地址绑定

第三步:recvfrom阻塞等待客户端的请求

recvfrom(2)

#include<sys/types.h>

#include<sys/socket.h>

ssize_trecvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr*src_addr, socklen_t *addrlen);

功能:从socket接受数据

参数:

sockfd:socket(2)返回值

buf:存放数据的内存的地址

len:从buf地址开始的字节数

flags:0

src_addr:数据发送者的ip地址和端口号

addrlen:发送者地址的长度

返回值:

接收到的字节数

-1表示错误

第四步:数据处理

第五步:给客户端发送应答数据

sendto(2)

#include<sys/types.h>

#include<sys/socket.h>

ssize_tsendto(int sockfd, const void *buf, size_t len, int flags, const structsockaddr *dest_addr, socklen_t addrlen);

功能:通过socket传输数据

参数:

sockfd:

buf:

 

b) 基于UDP实现客户端

第一步:创建一个socket

第二步:直接给服务器发送数据请求

第三步:阻塞等待服务器的应答

第四步:关闭文件描述符

举例:vi udpserv.c

  1 #include<stdio.h>

  2 #include<sys/types.h>

  3 #include<sys/socket.h>

  4 #include<stdlib.h>

  5 #include<ctype.h>

  6 #include<netinet/in.h>

  7 #include<strings.h>

  8 int main(void){

  9    int s_fd,n;

 10    char buf[32];

 11    struct sockaddr_in servaddr,cliaddr;

 12    //创建socket

 13    s_fd=socket(AF_INET,SOCK_DGRAM,0);

 14    if(s_fd==-1){

 15        perror("socket");

 16        return 1;

 17     }

 18    bzero(&servaddr,sizeof(servaddr));

 19    servaddr.sin_family=AF_INET;

 20    servaddr.sin_port=htons(4777);

 21    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);

 22    //将s_fd和服务器的地址绑定

 23    bind(s_fd,(struct sockaddr *)&servaddr,sizeof(servaddr));

24     printf("bind...\n");

 25    while(1){

 26        int cliaddr_len=sizeof(cliaddr);

 27        //接收客户端的数据

 28        n=recvfrom(s_fd,buf,128,0,(struct sockaddr *)&cliaddr,&cliaddr_len);

 29        if(n==-1){

 30            perror("recvfrom");

 31            return 2;

 32        }

 33        for(int i=0;i<n;i++){

 34            buf[i]=toupper(buf[i]);

 35        }

 36        //发送数据给客户端

 37        sendto(s_fd,buf,n,0,(struct sockaddr *)&cliaddr,\

 38                 sizeof(cliaddr));

 39     }

 40    return 0;

 41 }

 

vi client.c

  1 #include<stdio.h>

  2 #include<sys/types.h>

  3 #include<sys/socket.h>

  4 #include<stdlib.h>

  5 #include<netinet/in.h>

  6 #include<strings.h>

  7 #include<string.h>

  8 typedef struct sockaddr sa;

  9 typedef struct sockaddr_in  sa_i;

 10 int main(void){

 11    //初始化

 12    int s_fd,n;

 13    sa_i servaddr,cliaddr;

 14    char buf[128];

 15    s_fd=socket(AF_INET,SOCK_DGRAM,0);

 16    bzero(&servaddr,sizeof(servaddr));

 17    servaddr.sin_family=AF_INET;

 18    servaddr.sin_port=htons(4777);

 19     inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr);

 20    //发送数据给服务器

 21    while(fgets(buf,128,stdin)!=NULL){

 22        sendto(s_fd,buf,strlen(buf),0,\

 23        (sa *)&servaddr,sizeof(servaddr));

 24        n=recvfrom(s_fd,buf,128,0,NULL,0);

 25        write(1,buf,n);

 26     }

 27    close(s_fd);

 28    return 0;

 29 }

tarena@tarena-virtual-machine:~/day34$gcc udpserv.c -o server -std=c99

tarena@tarena-virtual-machine:~/day34$gcc udpcli.c -o client -std=c99

在一个终端开启服务器

tarena@tarena-virtual-machine:~/day34$./server

bind...

在另一个终端开启客户端

tarena@tarena-virtual-machine:~/day34$./client

tang

TANG

hello tang

HELLO TANG

(输入小写,自动转换大写)

三、线程的基本概念

a)      什么是线程?

线程是程序执行的基本单位

注意:

进程和线程的关系

进程是资源分配的基本单位。一个进程可以同时拥有多个线程,即同时被系统调度的多条执行路线,但至少要有一个主线程。进程中的所有线程共享进程的资源。

由于多个线程共享进程的资源,所以线程的切换的资源开销远远小于进程的切换。

每个线程都有自己的线程号,成为tid。 Thread

b)     创建线程

pthread_create(3)

#include<pthread.h>

intpthread_create(pthread_t *thread, const pthread_attr_t *attr,  void *(*start_routine) (void *), void *arg);

Compile and linkwith -pthread

功能:创建一个新的线程

参数:

thread:用于存放线程id

attr:NULL

start_routine:指向线程执行的函数的指针

arg:是第三个函数的参数

返回值:

0:成功

非0:失败

pthread_self(3)

#include<pthread.h>

pthread_tpthread_self(void);

功能:获取这个线程自己的tid

返回值:返回线程的id

举例:创建一个线程。  thread.c

  1 #include<stdio.h>

  2 #include<pthread.h>

  3 #include<sys/types.h>

  4 #include<unistd.h>

  5 pthread_t tid;

  6 void printids(const char *s){

  7    pthread_t ntid;

  8    printf("s=%s\n",s);

  9    printf("pid=%d\ttid=%lu\n",getpid(),pthread_self());

 10 }

 11 //线程的执行函数

 12 void *func(void *arg){

 13    int i;

 14    printids(arg);

 15    pthread_exit(&i);

17 }

 18 int main(void){//此时进程开始创建运行,同时创建出主线程

 19    pthread_create(&tid,NULL,func,"hello");//创建子线程

 20     printids("mainthread");

 21     sleep(1);

 22    return 0;

 23 }tarena@tarena-virtual-machine:~/day34$ gccthread.c -lpthread -o thread

tarena@tarena-virtual-machine:~/day34$./thread

s=main thread

pid=3560 tid=3075634880

s=hello

pid=3560 tid=3075631936

 

若:17    pthread_create(&tid,N
4000
ULL,func,"hello");

 18    sleep(1);

 19     printids("mainthread");

s=hello

pid=3671 tid=3075795776

s=main thread

pid=3671 tid=3075798720

主线程等了1s

线程的终止

不要使用exit退出进程

pthread_exit实现线程的退出

11 //线程的执行函数

 12 void *func(void *arg){

 13    int i;

 14    printids(arg);

 15    pthread_exit(&i);

 16    return NULL;

汇合线程

等待线程终止并与之汇合,同时回收该线程的资源

pthread_join(3)

#include<pthread.h>

intpthread_join(pthread_t thread, void **retval);

Compile and linkwith -pthread.

返回值:

0成功

参数:

thread:等待的那个线程

retval:存放的是thread那个线程的退出状态

举例:join.c

  1 #include<stdio.h>

  2 #include<pthread.h>

  3

  4 void *th_fn1(void *arg){

  5    printf("thread1 returning...\n");

  6    return (void *)1;

  7 }

  8 void *th_fn2(void *arg){

  9    printf("thread2 exit...\n");

 10    pthread_exit((void *)2);

 11 }

 12 int main(void){

 13    pthread_t tid;

 14    void *ret;

 15    pthread_create(&tid,NULL,th_fn1,NULL);

 16    pthread_join(tid,&ret);

 17    printf("thread1 exit code %d\n",(int)ret);

 18

 19    pthread_create(&tid,NULL,th_fn2,NULL);

 20    pthread_join(tid,&ret);

 21    printf("thread2 exit code %d\n",(int)ret);

 22    return 0;

 23 }

创建了两个子线程,加上主线程共有3个线程,join是主线程等待子线程

tarena@tarena-virtual-machine:~/day34$gcc join.c -lpthread -o join

tarena@tarena-virtual-machine:~/day34$./join

thread1returning...

thread1 exitcode 1

thread2 exit...

thread2 exitcode 2

如果  //   16    pthread_join(tid,&ret);

则:tarena@tarena-virtual-machine:~/day34$ ./join

thread1 exitcode -1217191948

thread2 exit...

thread1returning...

thread2 exitcode 2

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: