Linux网络编程之多线程并发服务器

思路:
1、主控线程等待接受连接请求
2、子线程 负责通信

在这里插入图片描述

多线程并发服务器伪代码:

typedef struct sockInfo{
pthread_t id;
int fd;
struct sockaddr_in addr;
}SockInfo;
void work(void * arg)
{
  while()
  {
     //打印客户端ip和port;
     read();
     write();
  }
}

int main()
{
  //监听
  int lfd = sock();
  //绑定
  bind();
  //设置监听
  listen(lfd,);
SockInfo sock_cfds[256];
//父线程
while(1)
{
  sock_cfds[i].fd = accept(lfd,&client,&len);
  //创建子线程
  pthread_create(&sock_cfds[i].id,NULL,work,&sock_cfds[i);
pthread_detch(&sock_cfd[i].id); 
 }
 }

代码实现:
server.c

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>

#include "wrap.h"

#define MAXLINE 8192
#define SERV_PORT 8000

struct s_info 
{    //定义一个结构体, 将地址结构跟cfd捆绑
    struct sockaddr_in cliaddr;
    int connfd;
    pthread_t id;
};


void * work(void *arg)
{
	int n,i;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN]; 
	struct s_info  * ts = (struct  s_info *)arg;
 while(1)
 {
    n = Read(ts->connfd,buf,MAXLINE);
    if(n == 0)
    {
      printf("the client %d close..\n",ts->connfd);
      break;
    }
    //打印客户端信息(IP/PORT)
  printf("received from %s at PORT %d\n",
                inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
                ntohs((*ts).cliaddr.sin_port));                 
 
 }
 //小写转大写
 for(i = 0; i < n; i ++)
 {
    buf[i] = toupper(buf[i]);
 }
 //写回屏幕
  Write(STDOUT_FILENO, buf, n);                           //写出客户端
 Write(ts->connfd, buf, n);          
}

int main()
{
  struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    pthread_t tid;
    struct s_info ts[256];//根据最大线程数创建结构体数组.
    int i = 0;

listenfd =  Socket(AF_INET, SOCK_STREAM, 0);                     //创建一个socket, 得到lfd
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr_s_addr = htonl(INADDR_ANY);                   //指定本地任意IP)
servaddr_sin_port(htons(SERV_PORT));
  Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); //绑定
Listen(listenfd, 128);      //设置同一时刻链接服务器上限数
printf("Accepting client connect ...\n");

while(1)
{
//主线程--等待接受连接
   cliaddr_len = sizeof(cliaddr);
  connefd = accept(&listenfd,(struct sockaddr*)cliaddr,&cliaddr_len);//阻塞监听客户端链接请求
  ts[i].cliaddr = cliaddr;
 ts[i].connfd = connfd; 
 pthread_creat(&ts[i].id,NULL,work,(void *)&ts[i]);
 pthread_detach(&ts[i].id);
 i ++;
 if(i == 256)
 break;
}
//主控线程退出
return 0;

}

client.c

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "wrap.h"

#define MAXLINE 80
#define SERV_PORT 8000
int main(int argc, char *argv[])
{
  sock_addr_in servaddr,cliaddr;
  sock_len_t  serv len,clialen;
  int fd ;
  fd = sock(AF_INET,SCOK_STREAM,0)bsero(&servaddr,sizeof9servaddr));
  servaddr_sin_family = AF_INET;
  inet_pton(AF_INET,"127.0.0.1",&servaddr_sin_addr.s_addr);
  servaddr_sin_port = htons(SERV_PORT );
  connect(fd,struct sock_addr *)servaddr,&servlen);
  while(fgets(buf,MAXLINE ,STDIN) != null)
  {
      write(fd,buf,strlen(buf));
      n = Read(sockfd,buf,MAXLINE);
      if( n == 0)
      printf("the other side has been close.\n");
      else
      Write(STDOUT_FILENO,buf,n);
  }
  close(fd);
  return 0;
 
}

wrap.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>

void perr_exit(const char *s)
{
	perror(s);
	exit(-1);
}

int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
	int n;

again:
	if ((n = accept(fd, sa, salenptr)) < 0) {
		if ((errno == ECONNABORTED) || (errno == EINTR))
			goto again;
		else
			perr_exit("accept error");
	}
	return n;
}

int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

	if ((n = bind(fd, sa, salen)) < 0)
		perr_exit("bind error");

    return n;
}

int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

	if ((n = connect(fd, sa, salen)) < 0)
		perr_exit("connect error");

    return n;
}

int Listen(int fd, int backlog)
{
    int n;

	if ((n = listen(fd, backlog)) < 0)
		perr_exit("listen error");

    return n;
}

int Socket(int family, int type, int protocol)
{
	int n;

	if ((n = socket(family, type, protocol)) < 0)
		perr_exit("socket error");

	return n;
}

ssize_t Read(int fd, void *ptr, size_t nbytes)
{
	ssize_t n;

again:
	if ( (n = read(fd, ptr, nbytes)) == -1) {
		if (errno == EINTR)
			goto again;
		else
			return -1;
	}
	return n;
}

ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
	ssize_t n;

again:
	if ( (n = write(fd, ptr, nbytes)) == -1) {
		if (errno == EINTR)
			goto again;
		else
			return -1;
	}
	return n;
}

int Close(int fd)
{
    int n;
	if ((n = close(fd)) == -1)
		perr_exit("close error");

    return n;
}

/*参三: 应该读取的字节数*/
ssize_t Readn(int fd, void *vptr, size_t n)
{
	size_t  nleft;              //usigned int 剩余未读取的字节数
	ssize_t nread;              //int 实际读到的字节数
	char   *ptr;

	ptr = vptr;
	nleft = n;

	while (nleft > 0) {
		if ((nread = read(fd, ptr, nleft)) < 0) {
			if (errno == EINTR)
				nread = 0;
			else
				return -1;
		} else if (nread == 0)
			break;

		nleft -= nread;
		ptr += nread;
	}
	return n - nleft;
}

ssize_t Writen(int fd, const void *vptr, size_t n)
{
	size_t nleft;
	ssize_t nwritten;
	const char *ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
			if (nwritten < 0 && errno == EINTR)
				nwritten = 0;
			else
				return -1;
		}

		nleft -= nwritten;
		ptr += nwritten;
	}
	return n;
}

static ssize_t my_read(int fd, char *ptr)
{
	static int read_cnt;
	static char *read_ptr;
	static char read_buf[100];

	if (read_cnt <= 0) {
again:
		if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
			if (errno == EINTR)
				goto again;
			return -1;
		} else if (read_cnt == 0)
			return 0;
		read_ptr = read_buf;
	}
	read_cnt--;
	*ptr = *read_ptr++;

	return 1;
}

ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
	ssize_t n, rc;
	char    c, *ptr;

	ptr = vptr;
	for (n = 1; n < maxlen; n++) {
		if ( (rc = my_read(fd, &c)) == 1) {
			*ptr++ = c;
			if (c  == '\n')
				break;
		} else if (rc == 0) {
			*ptr = 0;
			return n - 1;
		} else
			return -1;
	}
	*ptr  = 0;

	return n;
}


输出:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值