并发概念: 并发是指两个或多个事件在同一时间间隔
发生; 多线程实现TCP并发服务器的实现流程: 一、创建套接字(socket函数): 通信域选择IPV4网络协议、套接字类型选择流式;
int sockfd = socket ( AF_INET, SOCK_STREAM, 0 ) ;
二、填充服务器的网络信息结构体: 1.定义网络信息结构体变量; 2.求出结构体变量的内存空间大小; 3.结构体清零; 4.使用IPV4网络协议; 5.预留给在终端输入的IP地址; 6.预留给在终端输入的网络字节序的端口号;
struct sockaddr_in serveraddr; socklen_t serveraddrlen = sizeof ( serveraddr) ; memset ( & serveraddr, 0 , serveraddrlen) ; serveraddr. sin_family = AF_INET; serveraddr. sin_addr. s_addr = inet_addr ( argv[ 1 ] ) ; serveraddr. sin_port = htons ( atoi ( argv[ 2 ] ) ) ;
三、套接字和服务器的网络信息结构体进行绑定(bind函数):
int ret = bind ( sockfd, ( struct sockaddr * ) & serveraddr, serveraddrlen) ;
int ret1 = listen ( sockfd, 5 ) ;
if ( - 1 == ( info. accept_fd = accept ( sockfd, ( struct sockaddr * ) & ( info. clientaddr) , & clientaddr_len) ) ) { perror ( "accept error" ) ; exit ( - 1 ) ; }
六、若有客户端连接成功,就创建线程,专门用来和该客户端通信(pthread_create函数):
if ( 0 != ( ret1 = pthread_create ( & thread_id, NULL , message_handling, & info) ) ) { printf ( "pthread_create error : errno = [%d] errstr = [%s]\n" , ret1, strerror ( ret1) ) ; exit ( EXIT_FAILURE) ; }
七、将线程设置成分离属性,线程结束后由操作系统回收资源(pthread_detach函数):
if ( 0 != ( ret2 = pthread_detach ( thread_id) ) ) { printf ( "pthread_create error : errno = [%d] errstr = [%s]\n" , ret2, strerror ( ret2) ) ; exit ( EXIT_FAILURE) ; }
八、创建线程处理函数用来接收来自客户端的数据(recv函数)和给客户端发送应答消息(send函数):
void * message_handling ( void * arg) ; int nbytes = recv ( acceptfd, buf, sizeof ( buf) , 0 ) ; printf ( "客户端发来数据[%s]\n" , buf) ; strcat ( buf, "----k" ) ; int ret2 = send ( acceptfd, buf, sizeof ( buf) , 0 ) ;
九、退出线程(pthread_exit函数)和关闭套接字(close函数):
close ( info. accept_fd) ; pthread_exit ( NULL ) ;
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <pthread.h>
# include <stdbool.h>
# include <netinet/in.h>
# include <netinet/ip.h>
# include <arpa/inet.h>
# include <unistd.h> typedef struct INFO
{ int accept_fd; struct sockaddr_in clientaddr; } info_t ;
void * message_handling ( void * arg) ; int main ( int argc, char const * argv[ ] )
{ if ( 3 != argc) { printf ( "Usage : %s <IP> <PORT>\n" , argv[ 0 ] ) ; exit ( - 1 ) ; } int sockfd = socket ( AF_INET, SOCK_STREAM, 0 ) ; if ( - 1 == sockfd) { perror ( "socket error" ) ; exit ( - 1 ) ; } struct sockaddr_in serveraddr; socklen_t serveraddr_len = sizeof ( serveraddr) ; memset ( & serveraddr, 0 , serveraddr_len) ; serveraddr. sin_family = AF_INET; serveraddr. sin_addr. s_addr = inet_addr ( argv[ 1 ] ) ; serveraddr. sin_port = htons ( atoi ( argv[ 2 ] ) ) ; if ( - 1 == bind ( sockfd, ( struct sockaddr * ) & serveraddr, serveraddr_len) ) { perror ( "bind error" ) ; exit ( - 1 ) ; } if ( - 1 == listen ( sockfd, 5 ) ) { perror ( "listen error" ) ; exit ( - 1 ) ; } info_t info; pthread_t thread_id; int ret1 = 0 ; int ret2 = 0 ; socklen_t clientaddr_len = sizeof ( info. clientaddr) ; while ( true) { if ( - 1 == ( info. accept_fd = accept ( sockfd, ( struct sockaddr * ) & ( info. clientaddr) , & clientaddr_len) ) ) { perror ( "accept error" ) ; exit ( - 1 ) ; } if ( 0 != ( ret1 = pthread_create ( & thread_id, NULL , message_handling, & info) ) ) { printf ( "pthread_create error : errno = [%d] errstr = [%s]\n" , ret1, strerror ( ret1) ) ; exit ( EXIT_FAILURE) ; } if ( 0 != ( ret2 = pthread_detach ( thread_id) ) ) { printf ( "pthread_create error : errno = [%d] errstr = [%s]\n" , ret2, strerror ( ret2) ) ; exit ( EXIT_FAILURE) ; } } close ( sockfd) ; return 0 ;
} void * message_handling ( void * arg)
{ info_t info = * ( info_t * ) arg; printf ( "客户端[%s : %d]连接到服务器\n" , inet_ntoa ( info. clientaddr. sin_addr) , ntohs ( info. clientaddr. sin_port) ) ; int nbytes = 0 ; char buf[ 128 ] = { 0 } ; while ( true) { memset ( buf, 0 , sizeof ( buf) ) ; if ( - 1 == ( nbytes = recv ( info. accept_fd, buf, sizeof ( buf) , 0 ) ) ) { perror ( "recv error" ) ; break ; } else if ( 0 == nbytes) { printf ( "客户端[%s : %d]断开了连接\n" , inet_ntoa ( info. clientaddr. sin_addr) , ntohs ( info. clientaddr. sin_port) ) ; break ; } if ( ! strcmp ( buf, "quit" ) ) { printf ( "客户端[%s : %d]退出了\n" , inet_ntoa ( info. clientaddr. sin_addr) , ntohs ( info. clientaddr. sin_port) ) ; break ; } printf ( "客户端[%s : %d]发来消息[%s]\n" , inet_ntoa ( info. clientaddr. sin_addr) , ntohs ( info. clientaddr. sin_port) , buf) ; strcat ( buf, "------k" ) ; if ( - 1 == send ( info. accept_fd, buf, sizeof ( buf) , 0 ) ) { perror ( "send error" ) ; break ; } } close ( info. accept_fd) ; pthread_exit ( NULL ) ; }