我们都知道socket函数执行成功时,返回一个可用的套接字描述符(套接字描述符实质上是一个无符号整数)。但每个进程维护一套套接字描述符还是每个线程维护一套呢?看下面的程序。
1. 不同进程同时使用socket
下面的代码socket_rst.c循环执行socket函数,申请套接字描述符。
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #define MAX_NUM 10 int main(int argc, char *argv[]) { int fd[MAX_NUM]; int i; if (argc != 2) { printf("Usage: %s arg1n", argv[0]); return -1; } for (i = 0; i < MAX_NUM; i++) { if ((fd[i] = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("create socket %d errorn", i); return -1; } printf("%s: socket[%d] = %dn",argv[1], i, fd[i]); sleep(1); } return 0; }
编译(gcc socket_rst.c -o socket_rst )后,我们同时启动两个进程,进程运行结果如下:
allan@ubuntu:workspace$ ./socket_rst process1 & ./socket_rst process2 & [1] 17823 [2] 17824 allan@ubuntu:workspace$ process1: socket[0] = 3 process2: socket[0] = 3 process1: socket[1] = 4 process2: socket[1] = 4 process1: socket[2] = 5 process2: socket[2] = 5 process1: socket[3] = 6 process2: socket[3] = 6 process1: socket[4] = 7 process2: socket[4] = 7 process2: socket[5] = 8 process1: socket[5] = 8 process1: socket[6] = 9 process2: socket[6] = 9 process1: socket[7] = 10 process2: socket[7] = 10 process1: socket[8] = 11 process2: socket[8] = 11 process1: socket[9] = 12 process2: socket[9] = 12 [1]- Done ./socket_rst process1 [2]+ Done ./socket_rst process2 allan@ubuntu:workspace$
可以看到两个进程的到的套接字描述符是相互没有影响的。
2. 不同线程同时使用socket
下面的代码socket_rst_thread.c中,进程创建一个线程,主线程(进程)和子线程中同时执行socket函数申请套接字描述符:
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <pthread.h> #define MAX_NUM 10 void * thread_func() { int fd_thread[MAX_NUM]; int i; for (i = 0; i < MAX_NUM; i++) { if ((fd_thread[i] = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("create socket %d errorn", i); exit(-1); } printf("Thread: socket[%d] = %dn", i, fd_thread[i]); sleep(1); } } int main(int argc, char *argv[]) { int fd[MAX_NUM]; int i, status; pthread_t tid; void *exit_value; if (( status = pthread_create(&tid, NULL, thread_func, NULL)) != 0) { perror("Thread creation error."); return -1; } for (i = 0; i < MAX_NUM; i++) { if ((fd[i] = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("create socket %d errorn", i); return -1; } printf("Main: socket[%d] = %dn", i, fd[i]); sleep(1); } if ((status = pthread_join(tid, &exit_value)) != 0) { perror("Thread join error"); return -1; } return 0; }
编译(gcc socket_rst_thread.c -o socket_rst_thread -lpthread )后,程序运行结果如下:
allan@ubuntu:workspace$ ./socket_rst_thread Main: socket[0] = 3 Thread: socket[0] = 4 Main: socket[1] = 5 Thread: socket[1] = 6 Main: socket[2] = 7 Thread: socket[2] = 8 Main: socket[3] = 9 Thread: socket[3] = 10 Main: socket[4] = 11 Thread: socket[4] = 12 Thread: socket[5] = 13 Main: socket[5] = 14 Thread: socket[6] = 15 Main: socket[6] = 16 Main: socket[7] = 17 Thread: socket[7] = 18 Main: socket[8] = 19 Thread: socket[8] = 20 Main: socket[9] = 21 Thread: socket[9] = 22 allan@ubuntu:workspace$
可以看到主线程和子线程共用的是同一个套接字描述符集。
3. 结论
从上面的代码以及对比中,我们可以得到以下结论:
- 描述符0、1、2分别为系统使用的stdin、stdout、stderr。所以我们程序申请可用的(套接字)描述符最小从3开始。
- 申请(套接字)描述符时,系统总是(不考虑异常情况下)返回最小的、可用的描述符(所以我们得到的描述符一般都是连续的)。
- 每个进程在自己的进程空间内维护一套自己的(套接字)描述符,进程内的线程共享这套描述符。不同进程间的描述符互不影响。
评论已关闭