网络编程实验3-并发多线程服务器设计

⽹络编程实验3-并发线程服务器设计⽹络编程实验3-并发多线程服务器设计
实验⽬的
本次实验的主要⽬的是使⽤多线程实现并发的,⾯向连接的服务器设计。
实验内容
1、设计多线程的,⾯向连接的并发服务器
2、改造客户端为⾯向连接的多线程客户端
基本概念
1、将线程⽤于并发的、⾯向连接服务器的算法
主1 创建套接字并将其绑定到所提供服务的熟知地址上。让该套接字保持⾮连接。
主2 将该端⼝设置为被动模式,使其准备为服务器所⽤。
主3 反复调⽤accept以便接受来⾃客户的下⼀个连接请求,并创建新的从线程来处理响应。
从1 由主线程传递来的连接请求(即针对连接的套接字)开始。
从2 ⽤该连接与客户进⾏交互:读取请求并发回响应。
从3 关闭连接并退出。在处理完来⾃客户的所有请求后,从线程就退出。
2、线程
线程是⼀个进程内部的⼀个控制序列,是⼀次独⽴的计算。
(1)创建线程
#include  <pthread.h>
int  pthread_create(pthread_t  thread,  pthread_attr_t  *attr,
void *(*start_routine)(void*), void *arg);
返回值: 0 成功 错误号表⽰失败。
thread: 指向pthread_t类型的变量,新创建的线程标识符;
attr:指向pthread_attr_t线程属性类型的变量,
start_routine: 指向线程函数的指针,线程要执⾏的代码。
arg: 指向线程参数的指针。
(2)终⽌线程
线程退出⽅式:
① 从线程函数中返回,返回值为线程的退出码;
return(retu_val);
② 被同⼀进程的其他线程终⽌,即被取消;
pthread_cancel;
③ 执⾏线程退出调⽤;
pthread_exit;
exit
线程退出:
#include <pthread.h>
void pthread_exit(void *retval);
*retval: void类型的指针。
线程终⽌:
#include <pthread.h>
int pthread_cancel(pthread_t  th);
返回值: 0 成功 错误号表⽰失败
(3)等待线程
等待线程的终⽌。
#include  <pthread.h>
int pthread_join(pthread_t  th, void **thread_return);
返回值:0 成功 错误码表⽰失败
(4)线程协调和同步
Linux的同步机制:
① 互斥( mutex)
② 信号量( semaphore)
③ 条件变量( condition variable)
(5)线程的属性
属性: 脱离线程(detached thread)
初始化属性对象
#include <pthread.h>
int  pthread_attr_init(pthread_attr_t  *attr);
返回码:成功 0
失败 错误代码
回收函数
Pthread_attr_destroy(pthread_attr_t *attr);
实验步骤
1.编写头⽂件sockutil.h
#ifndef SOCKUTIL_H
#define SOCKUTIL_H
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<netdb.h>
#ifndef INADDR_NONE
#define INADDR_NONE 0xFFFFFFFF
#endif
光导纤维照明int connectSock(char* host,char* service,char* protocol);
int passiveSock(char* service,char* protocol,int qlen);
void errexit(char* fmt,...);
#endif
2.创建sockutil.c⽂件,编写通⽤过程connectSock及passiveSock代码
#include "sockutil.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
int connectSock(char* host,char* service,char* protocol)
{
struct hostent* pHost;
struct servent* pServ;
struct protoent* pProto;
struct protoent* pProto;
struct sockaddr_in addr;
int s,type;
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
if((pHost=gethostbyname(host))!=NULL)
memcpy(&addr.sin_addr,pHost->h_addr,pHost->h_length);
else if((addr.sin_addr.s_addr=inet_addr(host))==INADDR_NONE)
errexit("can't get \"%s\" host entry",host);
if((pServ=getservbyname(service,protocol))!=NULL)
addr.sin_port=pServ->s_port;
else if((addr.sin_port=htons((unsigned short)atoi(service)))==0)
errexit("can't get \"%s\" service entry",service);
if((pProto=getprotobyname(protocol))==0)
errexit("can't get \"%s\" protocol entry",protocol);
if(strcmp(protocol,"tcp")==0)
type=SOCK_STREAM;
else
type=SOCK_DGRAM;
s=socket(PF_INET,type,pProto->p_proto);
if(s<0)
errexit("can't create socket");
if(connect(s,(struct sockaddr*)&addr,sizeof(addr))<0)
errexit("can't connect to %s:%s",host,service);
return s;
}
int passiveSock(char* service,char* protocol,int qlen)
{
struct servent* pServ;
struct protoent* pProto;
struct sockaddr_in addr;
int s,type,reuse=1;
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=INADDR_ANY;
if((pServ=getservbyname(service,protocol))!=NULL)
addr.sin_port=pServ->s_port;
else if((addr.sin_port=htons((unsigned short)atoi(service)))==0)
errexit("can't get \"%s\" service entry",service);
if((pProto=getprotobyname(protocol))==0)
errexit("can't get \"%s\" protocol entry",protocol);
if(strcmp(protocol,"tcp")==0)
type=SOCK_STREAM;
else
type=SOCK_DGRAM;
s=socket(PF_INET,type,pProto->p_proto);
if(s<0)
errexit("can't create socket");
if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(int))<0)                errexit("setsockopt err");
if(bind(s,(struct sockaddr*)&addr,sizeof(addr))<0)
errexit("can't bind to %s port",service);
if(type==SOCK_STREAM&&listen(s,qlen)<0)
errexit("can't to listen on %s port",service);
return s;
}
void errexit(char* fmt,...)
{
va_list arg_ptr;
va_start(arg_ptr,fmt);
vfprintf(stderr,fmt,arg_ptr);
fprintf(stderr,":%s.\n",strerror(errno));
va_end(arg_ptr);
exit(errno);
exit(errno);
}
3.编写头⽂件socklink.h
#ifndef SOCKLINK_H
#define SOCKLINK_H
#include<pthread.h>
typedef struct SockEle{
void* next;
int sock;
pthread_t tid;
}*pSockEle;
extern pSockEle linkHead,linkTail;
void linkInsert(int sock,pthread_t tid);
void linkDelete(int sock);
void linkPrint(void);
int linkGetSize(void);
#endif//SOCKLINK_H
4.编写socklink.c⽂件,⽤来存储发送的消息内容。
#include"socklink.h"
#include"sockutil.h"
#include<stdio.h>
#include<stdlib.h>
pSockEle linkHead,linkTail;
static int      linkSize;
static pSockEle Linkmalloc(int sock,pthread_t tid){
pSockEle p=(pSockEle)malloc(sizeof(struct SockEle));
p->sock=sock;
p->tid=tid;
p->next=NULL;
}
void linkInsert(int sock,pthread_t tid){
pSockEle p;三噻吩
if(sock<0)
errexit("linkInsert err");
p=Linkmalloc(sock,tid);
if(linkHead==NULL)
linkHead=linkTail=p;
else{
linkTail->next=p;
linkTail=p;
}
linkSize++;
}
金纳米颗粒void linkDelete(int sock){
pSockEle p,it;
if(sock<0)
errexit("linkDelete err");
for(p=linkHead;p!=NULL;p=p->next){
if(p->sock==sock){
if(linkHead==linkTail)
linkHead=linkTail=NULL;
else if(p==linkHead)
linkHead=linkHead->next;
三星m300
linkHead=linkHead->next;
else if(p==linkTail){
//出尾部元素的前⼀个对象
for(it=linkHead;it->next!=linkTail;it=it->next);
it->next=NULL;
linkTail=it;
}
else{
//出待删除元素的前⼀个对象
for(it=linkHead;it->next!=p;it=it->next);
it->next=p->next;
}
break;
}
}
if(p!=NULL){
free(p);
linkSize--;
}
}
void linkPrint(void) {
pSockEle p;
for(p=linkHead;p!=NULL;p=p->next)
printf("%d ",p->sock);
printf("\n");
}
int linkGetSize(void) {
return linkSize;
}
5.编写头⽂件server.h
雏鹰争章网
#ifndef SERVER_H
#define SERVER_H
#define QLEN 20
#define BUFSIZE 100
#endif
6.编写server.c⽂件,实现TCP多线程并发服务器
上海公共网
#include"server.h"
#include"sockutil.h"
#include"socklink.h"
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<errno.h>
#include<sys/signal.h>
#include<sys/select.h>
int sockFd;
pthread_mutex_t linkLock=PTHREAD_MUTEX_INITIALIZER;
void sigint_handler(int sig){
close(sockFd);
printf("\nConnection has closed.\n");
exit(0);
}
void* commWithClient(void* arg){

本文发布于:2024-09-22 19:18:57,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/137474.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:线程   连接   服务器   并发   请求   失败   退出   过程
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议