版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons)
一、实验目的和要求
1 了解TCP/IP协议
2 掌握Socket编程,熟悉基于TCP和UDP的传输模型
3 掌握多线程编程
4 掌握基于TCP的并发服务器设计
二、实验内容和原理
实验内容:编写C程序,利用多线程构建TCP并发服务器,并实现客户端和服务器的传输(多个并发用户同时访问服务器)
实验原理:TCP的传输模型和线程的并发执行
三、主要仪器设备
PC机、装有Linux操作系统的虚拟机
四、操作方法与实验步骤
线程并发客户端:
#include <netinet/in. h> // for sockaddr_ in
#include <sys/types. h> // for socket
#include <sys/ socket. h> // for socket
#include <stdio. h> // for printf :
#include <stdlib. h> . // for exit
#include <string. h> // for bzero
#include <pthread. h>
#include <sys/errno. h> // for errno
#define HELLO_WORLD_SERVER_PORT 6666
#define BUFFER_SIZE 1024
char * server_IP = NULL;
void * talk_to_server(void * thread_num)
{
struct sockaddr_in c1ient_addr ;
bzero (&c1ient_addr, sizeof (c1ient_addr)); //把一段内存区的内容全部没置カ0
client_addr.sin_family = AF_INET; //internet
client_addr.sin_addr.s_addr = htons (INADDR_ ANY);//INADDR_ ANY表示自劫荻取本机地址
c1ient_addr.sin_port = htons(0) ;
int client_socket = socket (AF_INET, SoCK_STREAMI, 0);
if( c1ient_socket<O)
{
printf ("Create Socket Failed!\n");
exit(1);
}
//把客戸机的socket和客戸机的socket地址結枸朕系起来
if( bind(c1ient_socket, (structsockaddr*)&client_addr, sizeof(c1ient_addr)))
{
printf("C1ient Bind Port Failed!\n");
exit(1);
}
//没置一-个socket地址結枸server_ addr, 代表服努器的internet地址,端ロ
struct sockaddr_in server_addr ;
bzero (&server_addr, sizeof (server_addr));
server_addr.sin_fami1y = AF_INET:
if(inet_aton (server_IP, &server_addr.sin_addr) == 0) //服务器的IP地址来自程序的参数
{
printf("Server IP Address Error!\n");
exit(1);
}
server_addr.sin_port = htons (HELLO_WORLD_SERVER_P0RT);
sock1en_t server_addr_length = sizeof (server_addr);
if (connect (client_socket,(struct sockaddr* )&server_addr,server_addr_length) < 0)
{
printf("Can Not Connect To %s!\n" ,server_IP);
exit(1);
}
char buffer [BUFFER_SIZE];
bzero (buffer, BUFFER_SIZE),//从服务器接收数据到buffer中
int length =recv (client_socket, buffer, BUFFER_SIZE, 0);
if(length<0)
{
printf("Recieve Data From Server %s Failed!\n");
exit(1);
}
printf("From Server %s :\t%s",server_IP,buffer);
bzero(buffer,BUFFER_SIZE);
sprintf(buffer,"Hello,world! From Client Thread NUM :\t %d\n",(int)thread_num);
send(client_socket,buffer,BUFFER_SIZE,0);
close(client_socket);
pthread_exit(NULL);
}
int main(int argc,char **argv)
{
if (argc != 2)
{
printf("Usage: . /%s ServerIPAddress\n" , argv[0]);
exit(1) ;
}
server_IP = argv[1];
pthread_t child_thread;
pthread_attr_t child_thread_attr;
pthread_attr_init(&child_thread_attr);
pthread_attr_setdetachstate (&child_thread_attr, PTHREAD_CREATE_DETACHED);
int i=0;
for(i=0; i<10000; i++){
if(pthread_ create(&child_ thread, &child_thread_attr, talk_to_server, (void *)i)< 0 )
printf(" pthread_ create Failed : %s\n", strerror (errno)) ;
}
return 0;
}
线程并发服务器
#include <netinet/in.h> // for sockaddr_ in
#include <sys/types.h> // for socket
#include <sys/socket.h> // for socket
#include <stdio.h> // for printf :
#include <stdlib.h> . // for exit
#include <string.h> // for bzero
#include <pthread.h>
#include <sys/errno.h> // for errno
#define HELLO_WORLD_SERVER_PORT 6666
#define LENGTH_OF_LISTEN_QUEUE 20
#define THREAD_MAX 5
#define BUFFER_SIZE 1024
void * talk_to_client(void *data)
{
int new_server_socket = (int) data;
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
strcpy(buffer, "He11o, World!从服努器来!");
strcat(buffer,"\n");
send(new_server_socket, buffer, BUFFER _SIZE, 0);
bzero (buffer , BUFFR_SIZE):
int length = recv (new_server_socket, buffer, BUFFER_SIZE, 0);
if (length <0){
printf(" Server Recieve Data Failed!\n");
exit(1);}
printf(" \nSocket Num: %d \t %s", new_server_socket, buffer);
close(new_server_socket) ;
pthread_exit (NULL);
}
int main(int argc.char **argv)
{
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s=htons(INADDR_ANY);
server_addr.sin_port=htons(HELLO_WORLD_SERVER_PORT);
int server_socket=socket(AF_INET,SOCK_STREAM,0);
if(server_socket<0)
{
printf("Create Socket Failed!");
exit(1);
}
if(bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
{
printf("Server Bind Port: %d Failed!",HELLO_WORLD_SERVER_PORT);
exit(1);
}
if(listen(server_socket,LENGTH_OF_LISTEN_QUEUE))
{
printf("Server Listen Failed!");
exit(1);
}
while(1)
{
struct sockaddr_ in c1ient_addr :
socklen_t length = sizeof (c1ient_addr) ;
int new_server_socket=accept (server_socket, (struct sockaddr*)&c1ient_addr , &length);
if ( new_server_socket<O)
{
printf(" Server Accept Failed!\n");
break:
}
pthread_t chi1d_thread;
pthread_attr_t chi1d_thread_attr ;
pthread_attr_init(&chi1d_thread_attr);
pthread_attr_setdetachstate (&chi1d_thread_attr, PTHREAD_CREATE_DETACHED);
if( pthread_create (&chi1d_thread, &chi1d_thread_attr, talk_to_c1ient,(void *)new_server_socket) <0 )
printf("pthread_create Failed : %s\n", strerror (errno));
}
close(server_socket);
return 0;
}
五、实验数据和记录
服务器程序的编译
gcc thread_server1.c -1pthread –o thread_server1
客户端程序编译
gcc thread_client1.c -1pthread –o thread_client1
服务器程序合客户端应当分别在2个终端上。
服务器端程序的运行,在一个终端执行
./thread_server1
客户端程序在另一个终端执行
./thread_client1 127.0.0.1