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
用多进程实现为多个客户服务的例子
在服务器为每个客户创建一个进程,这个进程负责和客户的通讯
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
相关文章推荐
- Linux C UDP Socket实现客户与服务器简单通信
- tcp和udp多线程的epoll服务器+客户端源代码
- 初识用UDP协议做的windows窗口聊天程序---此处是双向的"异步"多线程对话框通信.
- socket客户端服务器通信(多线程)
- linux 网络编程:客户端与服务器通过TCP协议相互通信 + UDP
- linux 网络编程:客户端与服务器通过TCP协议相互通信 + UDP
- java 服务器与客户断对话,socket,多线程
- 【转】Socket 通信原理(Android客户端和服务器以TCP&&UDP方式互通)
- 网络程序设计--UDP通信(服务器)
- tcp和udp多线程的epoll服务器+客户端源代码
- linux中客户服务器通信程序(TCP)
- UDP协议做的windows窗口聊天程序---此处是单向的"同步"多线程对话框通信
- java socket实现的客户端和服务器端,服务器采用多线程实现,为每个客户分配一个线程
- linux下视频采集服务器(UDP传输、多线程模式)
- 基于UDP的多线程网络通信程序
- tcp和udp多线程的epoll服务器+客户端源代码
- 命名管道--简单的客户服务器通信
- 局域网聊天工具(多线程),支持客户端与客户端间通信,服务器负责信息的接收与发送
- Socket 通信原理(Android客户端和服务器以TCP&&UDP方式互通)
- Socket 通信原理 -- Android客户端和服务器以TCP&&UDP方式互通