socket套接字的使用

int socket(int family,int type,int protocol);

功能:创建一个通过tcp/ip协议发送和接收网络数据的Socket

返回值:成功返回Socket描述符,失败<0

参数:family:指明协议族(AF_INET,AF_INET6AF_LOCAL,AF_ROUTE,AF_KEY)

          type:指明套接字类型:(SOCKET_STREAM,SOCK_DGREAM,SOCK_SEQPACKET,SOCK_RAW)

          protocol: 指明协议类型,0时由family和type一起决定

Linux 内核将Socket描述符和文件进行统一管理,所以可以将Socket看做特殊文件

int close(int sockfd)

功能:关闭套接字

返回值:成功返回0,失败<0

参数:已经发开的套接字描述符


family决定地址类型:

当为AF_LOCAL(相当于AF_UNIX)

struct sockaddr_un

{

       sa_family_t      sun_family;    /*  AF_UNIX */

       char                   sun_path();     /*  pathname  */

}

当为AF_INET时:

struct sockaddr_in

{

           short   int                          sin_family   ;  /*  AF_INET  */

           unsignde   short  int        sin_port      ;   /*  port  number */

            struct  in_addr                 sin_addr    ;   /*   Internet address  */网络字节序

}


struct in_addr

{

        unsigned  long   int   s_addr    ;    //IP地址为 32 位  IPV 4 地址 网络字节序

}

后续Socket为了兼容更多类型,采用一下结构:

struct   socket

{

       short  int    sin_family;//协议族

       char           sa_data[14];//协议制定地址

}

在使用这些函数时候我们可以强制类型转换


主机字节序:某个给定的主机系统所用的字节序,它由cpu决定

网络字节序:网络协议制定的字节序,网络协议使用大端字节序来传送多字节整数

unsigned long int htonl(unsigned long int hostlong)

unsigned short int htons(unsigned short int hostshort)

unsigned long  int ntohl(unsigned long int netlong)

unsigned short int ntohs(unsigned short int netshort)

备注:h代表host  n代表network  s代表short   l代表long 


常用字节操作:

void *memset(void *dest,int ch,size_t len)

void *memcpy(void *dest,const void *src,size_t nbytes)

int memcmp(const void *ptr1,const void *ptr2,size_t nbytes)

void bzero(void *dest,size_t nbytes)等价于memset(dest,0,nbytes);


十进制与32位地址转换:

int inet_aton(const char *strptr,struct in_addr *addrptr)//字符串有效返回1,否则为0

char *inet_ntoa(struct in_addr  inaddr)

注: struct in_addr inaddr 均指网络字节序32位ip地址

      inet_ntoa 函数的结果位于静态数据区

域名与地址转换:

struct hostent  *gethostbyname(const char *hostname);

struct hostent *gethostbyaddr(const char *addr,size_t len,int family)//addr是struct in_addr


struct hostent 结构:


程序如下:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
	struct hostent * phost = NULL;
	struct in_addr *pinaddr = NULL;
	struct in_addr **ppinaddr = NULL;
	char *ip = NULL;
	char **ppaliases = NULL;

	phost = gethostbyname("www.sina.com.cn");
	printf("phost=%p\n",phost);
	ppinaddr = (struct in_addr **)phost->h_addr_list;
	while(*ppinaddr != NULL)
	{
		pinaddr = *ppinaddr;
		ip = inet_ntoa(*pinaddr);
		printf("ip=%s\n",ip);
		ppinaddr++;
	}
	
	printf("h_name=%s\n",phost->h_name);
	ppaliases = phost->h_aliases;
	while(*ppaliases != NULL)
	{
		printf("aliases = %s\n",*ppaliases);
		ppaliases++;
	}
	
	phost = gethostbyname("www.sohu.com");
	printf("phost=%p\n",phost);
	ppinaddr = (struct in_addr **)phost->h_addr_list;
	while(*ppinaddr != NULL)
	{
		pinaddr = *ppinaddr;
		ip = inet_ntoa(*pinaddr);
		printf("ip=%s\n",ip);
		ppinaddr++;
	}
	
	printf("h_name=%s\n",phost->h_name);
	ppaliases = phost->h_aliases;
	while(*ppaliases != NULL)
	{
		printf("aliases = %s\n",*ppaliases);
		ppaliases++;
	}
	return 0;
}



Socket 读写函数:

ssize_t read(int fd,void *buf,size_t count)//把fd内容读入buf

ssize_t write(int fd,const void *buf,size_t count)//把buf内容写入fd

ssize_t recv(int sockfd,void *buf,size_t nbytes,int flags)

ssize_t send(int sockfd,const void *buff,size_t nbytes,int flags)//send.recv为Socket专用

对于tcp而言,read,recv返回0表示远程socket已关闭

flags一般取0,也可以取以下内容:



tcp连接建立:

三次握手与四次挥手:

tcp连接范式:

客户端范式:

服务器范式:


关键函数:

int connect (int sockfd,const struct sockadr *servaddr,socklen_t addrlen)    /*   客户端连接服务器函数  */

功能:通过三路握手建立tcp服务器的连接

返回值:成功为0,失败<0

参数:sockfd:      sockfd函数返回的socket描述符

         servaddr:  指向与协议族相符的地址结构指针          /*  对于AF_INT协议族,其地址组成为IP地址+端口号,机构为:struct sockaddr_in   */

         addrlen:     实际地址结构大小


int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen)      /*  一般用于服务器自身socket与本地地址绑定   */

功能:将本地协议地址赋予指定的socket描述符

          返回值: 成功为0,失败<0

参数:  sockfd:    sockfd函数返回的sockfd描述符

           myaddr:   指向与协议族相同的地址结构指针

           addrlen:    实际地址大小


int listen(int sockfd,int backlog)       /*  服务器   */

功能:将主动套接字改为被动套接字(用来接受向该套接字的连接请求)并设定套接字排队最大连接个数.

       返回值:成功返回0,失败<0

参数: sockfd: 处于未连接的套接字描述符

          backlog: 制定管理连接请求的队列长度,一般为5-20,大型服务器则为系统能支持的最大数

内核针对每个被动套接字采用两个队列管理连接请求:

未完成连接队列   and   已完成连接队列

  !!  该函数不会阻塞


int accept(int sockfd,struct sockaddr *cliaddr, socklen_t *addrlen)        /*服务器   */

功能:从已完成连接队列的队头返回一个已完成连接,空队列则阻塞等待已完成连接

          返回值: 成功返回已完成连接对应的socket描述符,服务器通过这个描述符与请求连接的客户端进行数据传输,失败<0,即已连接套接字

参数:

sockfd;监听套接字(即服务器用来处理连接请求的被动套接字)

cliaddr:返回已连接的对端进程(客户端)的协议地址

addrlen:调用前指定cliaddr的地址结构长度,返回后保存对应地址结构的确切字节数

!!  注意区分监听套接字与已连接套接字

不关系客户端地址cliaddr和addrlen 可以设为NULL

本函数会阻塞

 

未连接UDP 范式:

已连接UDP范式:



ssize_t sendto (int sockfd,const void *buff,size_t nbytes,int flags,const struct sockaddr *to,socklen_t addrlen)

功能:向指定地址发送期望字节数量的数据

返回值:成功返回实际发送的字节数,失败<0

参数:sockfd.buff,nbytes,flags:与send函数一样

to: 指向接收者的协议地址结构指针 (类似于connect对应参数的含义)

addrlen: to 所用的地址结构的字节长度 (类似于connect对应参数含义)


ssize_t recvfrom (int sockfd,void *buff,size_t bytes,int flags,struct sockaddr *from, socklen_t *addrlen)

功能:从指定的udp socket里面接收数据,同时填充发送发的协议地址结构

返回值:成功返回接收到的字节数,失败<0

参数:sockfd,buff,nbytes,flags 含义同recv函数

        from: 指向发送发的协议地址结构指针,类似于accept对应的参数含义,用于保存发送发地址,便于通过sendto回应对方相应数据.

        addrlen :from所用的地址结构的字节长度,类似于accept对应参数的含义,指出实际使用的地址结构长度。

      返回0是可接受的正确的结果,并非表示socket关闭,意味着可以发送空的UDP数据报(只有UDP首部而没有数据部分)给远端进程。

       from和addrlen可以同时为NULL,表示不关心发送方地址信息。

未连接UDP socket不足之处

             知道客户端临时端口和地址的任何进程都可以向其发送UDP包,客户端需要区分哪些包是自己期望的包(比如可以通过recvfrom的最后两个参数与期望服务器的协议地址比较来区分)

               如果服务器进程未启动,客户端将永久阻塞在recvfrom,无法获取相关错误信息。内核在发送UDP数据前有一个使用ARP协议验证服务器地址的过程,这个过程如果发现错误,内核却无法将此错误返回给sendto,除非这个UDP是一个已连接的UDP


非阻塞式I/O 实现函数:

fcntl(int fd,int cmd,long arg)

int flag;

flag=fcntl(sockfd,F_GETFL,0);

flag |= O_NONBLOCK;

fcntl(sockfd,F_SETFL,flag);


多路复用:

int select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout);

select()用来等待文件描述词状态的改变。参数n代表最大的文件描述词加1,参数readfds、writefds 和exceptfds 称为描述词组,是用来回传该描述词的读,写或例外的状况。底下的宏提供了处理这三种描述词组的方式:

FD_CLR(inr fd,fd_set* set);用来清除描述词组set中相关fd 的位

FD_ISSET(int fd,fd_set *set);用来测试描述词组set中相关fd 的位是否为真

FD_SET(int fd,fd_set*set);用来设置描述词组set中相关fd的位

FD_ZERO(fd_set *set);用来清除描述词组set的全部位


getsockname/getpeername



getsockope /setsockopt



代码分析:

多进程进行通信:

客户端:

skywalker@skywalker:~/work/network/multiprocess$ cat client.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
	int	sockfd;
	int	stdinfd = 0;
	fd_set  rset;
	struct sockaddr_in	servaddr;
	int ret;

	sockfd = socket(AF_INET, SOCK_STREAM, 0);//建立套接字

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(5678);
	inet_aton("127.0.0.1", &servaddr.sin_addr);

	connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));//connect服务器,sockaddr_in 强制转换为aockaddr

	while(1)
	{
		FD_ZERO(&rset);
		FD_SET(stdinfd,&rset);
		FD_SET(sockfd,&rset);
		ret = select(sockfd + 1,&rset,NULL,NULL,NULL);//多路复用
		if(ret <= 0)
		{
			if(errno == EINTR)
			{
				continue;
			}
			else
			{
				break;
			}
		}
		if(FD_ISSET(stdinfd,&rset))//终端输入
		{
			char buf[20] = {'\0'};
			int len = 0;
			int isexit = 0;
			do
			{
				bzero(buf,20);
				fgets(buf,20,stdin);//fgets函数读不玩的内容下次循环在缓冲器继续读取,fgts默认尾部加'\0'
				if(strcmp(buf,"quit\n") == 0)
				{
					isexit = 1;
					break;
				}
				len = strlen(buf);
				if(buf[len - 1] == '\n')
				{
					buf[len - 1] = '\0';
					write(sockfd,buf,len);
					break;
				}
				write(sockfd,buf,len);
			}while(buf[18] != '\0');
			if(isexit)
			{
				break;
			}
		}
		if(FD_ISSET(sockfd,&rset))//接收数据
		{
			int len;
			char buf[20] = {'\0'};
			write(1,"Client Say:",strlen("Client Say:"));
			len = read(sockfd,buf,20);
			if(len == 0)
			{
				break;
			}
			write(1,buf,len);
			while(len == 20  && buf[19] != '\0')
			{
				len = read(sockfd,buf,20);

				write(1,buf,len);
			}
			write(1,"\n",1);
		}
	}
	close(sockfd);
	exit(0);
}

服务器:

skywalker@skywalker:~/work/network/multiprocess$ cat server.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>

void HandleClient(int fd);
int main(int argc, char **argv)
{
	int	listenfd, connfd;
	socklen_t clilen;
	struct sockaddr_in	cliaddr, servaddr;
	int pid = -1;

	listenfd = socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family      = AF_INET;
	inet_aton("127.0.0.1", &(servaddr.sin_addr));
	servaddr.sin_port        = htons(5678);

	bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));//套接字与主机绑定

	listen(listenfd, 5);
	while(1)//每来一个客户端创建其子进程的子进程
	{
		connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);//等待接收客户端
		if(connfd > 0)
		{
			pid = fork();
			if(pid < 0)
			{
				printf("fork failed!!!\n");
				close(connfd);
			}
			else if(pid == 0)
			{
				pid = fork();
				if(pid < 0)
				{
					printf("fork failed!!!2\n");
					close(connfd);
				}
				else if(pid == 0)
				{
					close(listenfd);
					HandleClient(connfd);
					exit(0);
				}
				else
				{
					close(connfd);
					close(listenfd);
					exit(0);
				}
			}
			else
			{
				close(connfd);
				waitpid(pid,NULL,0);
			}
		}	
	}
	close(listenfd);
	return 0;
}

void HandleClient(int fd)
{
	int len;
	char buf[20];
	while(1)
	{
		len = read(fd,buf,20);
		if(len == 0)
		{
			close(fd);
			break;
		}
		write(1,"Server Say:",strlen("Server Say:"));
		write(1,buf,len);
		write(fd,buf,len);
		while(len == 20  && buf[19] != '\0')
		{
			len = read(fd,buf,20);
			write(1,buf,len);
			write(fd,buf,len);
		}
		write(1,"\n",1);
	}
}

使用select,数组存储套接字描述符,然后循环执行:

客户端:

skywalker@skywalker:~/work/network/selectecho$ cat client.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
	int	sockfd;
	int 	stdinfd = 0;
	fd_set  rset;
	struct sockaddr_in	servaddr;
	int ret;

	sockfd = socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(5678);
	inet_aton("127.0.0.1", &servaddr.sin_addr);

	connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

	while(1)
	{
		FD_ZERO(&rset);
		FD_SET(stdinfd,&rset);
		FD_SET(sockfd,&rset);
		ret = select(sockfd + 1,&rset,NULL,NULL,NULL);
		if(ret <= 0)
		{
			if(errno == EINTR)
			{
				continue;
			}
			else
			{
				break;
			}
		}
		if(FD_ISSET(stdinfd,&rset))
		{
			char buf[20] = {'\0'};
			int len = 0;
			int isexit = 0;
			do
			{
				bzero(buf,20);
				fgets(buf,20,stdin);
				if(strcmp(buf,"quit\n") == 0)
				{
					isexit = 1;
					break;
				}
				len = strlen(buf);
				if(buf[len - 1] == '\n')
				{
					buf[len - 1] = '\0';
					write(sockfd,buf,len);
					break;
				}
				write(sockfd,buf,len);
			}while(buf[18] != '\0');
			if(isexit)
			{
				break;
			}
		}
		if(FD_ISSET(sockfd,&rset))
		{
			int len;
			char buf[20] = {'\0'};
			write(1,"Client Say:",strlen("Client Say:"));
			len = read(sockfd,buf,20);
			if(len == 0)
			{
				break;
			}
			write(1,buf,len);
			while(len == 20  && buf[19] != '\0')
			{
				len = read(sockfd,buf,20);
				write(1,buf,len);
			}
			write(1,"\n",1);
		}
	}
	close(sockfd);
	exit(0);
}

服务器:

skywalker@skywalker:~/work/network/selectecho$ cat server.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>


int getMaxFd(int * pint,int size);
void addFd(int * pint,int size,int fd);
void setAllFd(int * pint,int size,fd_set * fdset);
int main(int argc, char **argv)
{
	int	listenfd, connfd;
	socklen_t clilen;
	struct sockaddr_in	cliaddr, servaddr;
	char buf[20] = {'\0'};
	fd_set rset;
	int maxfd;
	int ret;
	int clientfd[64] = {0};//用来存连接服务器的套接字
	int i = 0;

	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	memset(clientfd,0xff,sizeof(clientfd));

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family      = AF_INET;
	inet_aton("127.0.0.1", &(servaddr.sin_addr));
	servaddr.sin_port        = htons(5678);

	bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

	listen(listenfd, 5);

	maxfd = listenfd;
	for ( ; ; ) 
	{
		FD_ZERO(&rset);
		FD_SET(listenfd,&rset);
		setAllFd(clientfd,64,&rset);
		maxfd = getMaxFd(clientfd,64);
		if(maxfd < listenfd)
		{	
			maxfd = listenfd;
		}
		ret = select(maxfd+1,&rset,NULL,NULL,NULL);
		if(ret <= 0)
		{
			if(errno == EINTR)
			{
				continue;
			}
			else
			{
				break;
			}
		}
		if(FD_ISSET(listenfd,&rset))
		{
			clilen = sizeof(cliaddr);
			connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);//进行连接
			addFd(clientfd,64,connfd);//将此套接字加入到执行队列
		}
		for(i = 0; i < 64;i++)//对连接函数进行依次执行
		{
			if(clientfd[i] > 0)
			{
				if(FD_ISSET(clientfd[i],&rset))
				{
					int len;
					write(1,"Server Say:",strlen("Server Say:"));
					len = read(clientfd[i],buf,20);
					if(len == 0)
					{
						close(clientfd[i]);
						clientfd[i] = -1;
						continue;
					}
					write(1,buf,len);
					write(clientfd[i],buf,len);
					while(len == 20  && buf[19] != '\0')
					{
						len = read(clientfd[i],buf,20);
						write(1,buf,len);
						write(clientfd[i],buf,len);
					}
					write(1,"\n",1);
				}
			}
		}
	}
	close(listenfd);
	return 0;
}

int getMaxFd(int * pint,int size)
{
	int max = pint[0];
	int i = 0;
	for(i=1;i < size;i++)
	{
		if(max < pint[i])
		{
			max = pint[i];
		}
	}
	return max;
}

void addFd(int * pint,int size,int fd)
{
	int i = 0;
	for(i = 0; i < size;i++)
	{
		if(-1 == pint[i])
		{
			pint[i] = fd;
			break;
		}
	}	
}
void setAllFd(int * pint,int size,fd_set * fdset)
{
	int i = 0;
	for(i = 0; i < size;i++)
	{
		if(-1 != pint[i])
		{
			FD_SET(pint[i],fdset);
		}
	}	

}

多线程执行:

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
	int	sockfd;
	int 	stdinfd = 0;
	fd_set  rset;
	struct sockaddr_in	servaddr;
	int ret;

	sockfd = socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(5678);
	inet_aton("127.0.0.1", &servaddr.sin_addr);

	connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

	while(1)
	{
		FD_ZERO(&rset);
		FD_SET(stdinfd,&rset);
		FD_SET(sockfd,&rset);
		ret = select(sockfd + 1,&rset,NULL,NULL,NULL);
		if(ret <= 0)
		{
			if(errno == EINTR)
			{
				continue;
			}
			else
			{
				break;
			}
		}
		if(FD_ISSET(stdinfd,&rset))
		{
			char buf[20] = {'\0'};
			int len = 0;
			int isexit = 0;
			do
			{
				bzero(buf,20);
				fgets(buf,20,stdin);
				if(strcmp(buf,"quit\n") == 0)
				{
					isexit = 1;
					break;
				}
				len = strlen(buf);
				if(buf[len - 1] == '\n')
				{
					buf[len - 1] = '\0';
					write(sockfd,buf,len);
					break;
				}
				write(sockfd,buf,len);
			}while(buf[18] != '\0');
			if(isexit)
			{
				break;
			}
		}
		if(FD_ISSET(sockfd,&rset))
		{
			int len;
			char buf[20] = {'\0'};
                        write(1,"Client Say:",strlen("Client Say:"));
                        len = read(sockfd,buf,20);
			if(len == 0)
			{
				break;
			}
                        write(1,buf,len);
                        while(len == 20  && buf[19] != '\0')
                        {
                        	len = read(sockfd,buf,20);
                                write(1,buf,len);
                        }
                        write(1,"\n",1);
		}
	}
	close(sockfd);
	exit(0);
}

服务器:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>

void *HandleClient(void *arg);
int main(int argc, char **argv)
{
	int	listenfd, connfd;
	socklen_t clilen;
	struct sockaddr_in	cliaddr, servaddr;
	//int pid = -1;

	listenfd = socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family      = AF_INET;
	inet_aton("127.0.0.1", &(servaddr.sin_addr));
	servaddr.sin_port        = htons(5678);

	bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

	listen(listenfd, 5);
	while(1)
	{
		connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
		if(connfd > 0)
		{
	        	int err = 0;
        		pthread_t tid;
        		pthread_attr_t  attr;

        		err = pthread_attr_init(&attr);
        		err += pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
               	err += pthread_create(&tid, &attr,HandleClient, (void *)connfd);
        		pthread_attr_destroy(&attr);
		}	
	}
    close(listenfd);
	return 0;
}

void *HandleClient(void *arg)
{
	int len;
	int fd = (int)arg;
	char buf[20];
	while(1)
	{
		len = read(fd,buf,20);
		if(len == 0)
		{
			close(fd);
			break;
		}
		write(1,"Server Say:",strlen("Server Say:"));
		write(1,buf,len);
		write(fd,buf,len);
		while(len == 20  && buf[19] != '\0')
		{
			len = read(fd,buf,20);
			write(1,buf,len);
			write(fd,buf,len);
		}
        	write(1,"\n",1);
	}
	pthread_exit(NULL);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值