1. 程式人生 > >linux下的TCP小程式

linux下的TCP小程式

服務端是用多執行緒寫的併發伺服器,比較簡單。

功能:

1.  服務端執行後,即監聽指定的埠。允許多個連線併發執行

2.  服務端接收到客戶端請求後,根據客戶端傳過來的指令完成特定任務:

a)         向客戶端傳送服務端所在機器的當前時間

b)        向客戶端傳送服務端所在機器的名稱

c)         向客戶端傳送當前連線的所有客戶端資訊

d)        其它(向客戶端傳送鍵盤輸入的內容)

3.  客戶端執行後,可以執行以下任務:

a)         連線到指定地址和埠的服務端

b)        斷開與服務端的連線

c)         請求服務端給出當前時間

d)        請求服務端給出其機器的名稱

e)         請求服務端給出當前連線的所有客戶端資訊(編號、IP地址、埠等)

f)         給其他客戶端傳送鍵盤輸入的內容

g)        退出客戶端程式

h)        其它(向伺服器端傳送鍵盤輸入的內容)

客戶端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#include <unistd.h>
#include <time.h>

int main(int argc,char *argv[])
{
    int connect_fd;
	int ret;
	char snd_buf[1024];
	int i;
	int port;
	int len,lens;

	static struct sockaddr_in srv_addr;

	//判斷客戶端執行需要給出具體的連線地址和埠 
	if(argc!=3)
	{
	    printf("Usage: %s server_ip_address port\n",argv[0]);
		return 1;
	}

	//獲得輸入的埠
	port=atoi(argv[2]);

	//建立套節字用於客戶端的連線
	connect_fd=socket(PF_INET,SOCK_STREAM,0);
	if(connect_fd<0)
	{
	    perror("cannot create communication socket");
		return 1;
	}

	//填充關於伺服器的套節字資訊
	memset(&srv_addr,0,sizeof(srv_addr));
	srv_addr.sin_family=AF_INET;
	srv_addr.sin_addr.s_addr=inet_addr(argv[1]);
	srv_addr.sin_port=htons(port);

	//連線伺服器,如果連線失敗 ret==-1,結束程式 
	ret=connect(connect_fd,(struct sockaddr *)&srv_addr,sizeof(srv_addr));
	if(ret==-1)
	{
	    perror("cannot connect to the server");
		close(connect_fd);
		return 1;
	}

	memset(snd_buf,0,1024);
	//成功連線伺服器 
	while(1)
	{
	/*	time_t timeval;
		(void)time(&timeval);*/ 
		lens=strlen(ctime(&timeval));

	    	printf("Please input char:"); 
		fgets(snd_buf,1024,stdin); //鍵盤輸入內容 
		len = strlen(snd_buf);
		if(len>0)
		{
			write(connect_fd,snd_buf,len);//傳送資訊到伺服器 
		}
		len=read(connect_fd,snd_buf,1024);//如果伺服器發來資訊,則讀取,否則等待。。 
		if(len>0)
			printf("Message form server(%d): %s\n",len,snd_buf);//列印從伺服器收到的資訊 
		if(snd_buf[0]=='@')//@為退出字元。 跳出迴圈 
			break;
	}
	close(connect_fd);//斷開與伺服器的連線。 
	return 0;
}

服務端:

#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <netdb.h>
#include <time.h>
#include <stdlib.h>


struct sockaddr_in clt_addr;
struct sockaddr_in srv_addr;

//執行緒執行函式負責讀寫
void *thr_fn(void *arg)
{
	int size,j,lens;
	int *parg=(int *)arg;
	int new_fd=*parg;
	char recv_buf[1024];
	char hostdate[1024];
	char snd_buf[1024];

	fprintf(stderr,"Server get connection from %s\n",(char* )inet_ntoa(clt_addr.sin_addr));//顯示連線的客戶端ip,並打印出來 
	printf("new_fd=%d\n",new_fd);//客戶端連線編號 
	memset(snd_buf,0,1024);

	time_t timeval;
	(void)time(&timeval);

	while((size=read(new_fd,recv_buf,1024))>0)//判斷是否有客戶端傳送資訊過來 
	   {
			if(recv_buf[0]== '@')//exit
				break;
			if(recv_buf[0]== '!')//time
			{
				printf("Message from client(%d): %s\n",new_fd,recv_buf);
				lens=strlen(ctime(&timeval));
				write(new_fd,ctime(&timeval),lens);	
			}
			else if(recv_buf[0]== '#')//host message
			{
				char computer[256];
				struct utsname uts;
				if(gethostname(computer,255)!=0||uname(&uts)< 0)
				{
				fprintf(stderr, "Coule not get host information\n");
				exit(1);
				}
				lens=strlen(uts.nodename);
				char* hostdate=uts.nodename;
				printf("Message from client(%d): %s\n",new_fd,recv_buf);
				write(new_fd,hostdate,lens);			
			}
			else if(recv_buf[0]== '$')  
			{	
				
			}
			else
			{
			printf("Message from client(%d): %s\n",new_fd,recv_buf);
			}
			//伺服器向客戶端發信息 
		printf("Please input char:");
		fgets(snd_buf,1024,stdin); 
		write(new_fd,snd_buf,strlen(snd_buf)); 
		printf("\n");
	}
	close(new_fd);
	return 0;
}


int main(int argc,char *argv[])
{
    socklen_t clt_addr_len;
	int listen_fd;
	int com_fd;
	int ret;
	int i;
	static char recv_buf[1024];
	static char rev_buf[1024];
	int len;
	int port;
	pthread_t tid;

	//判斷客戶端是否填寫埠 
	if(argc!=2)   
	{
	    printf("Usage:%s port\n",argv[0]);
		return 1;
	}

	//埠的字元轉換 
	port=atoi(argv[1]);

	//建立套接字用於伺服器的監聽
	listen_fd=socket(PF_INET,SOCK_STREAM,0);
	if(listen_fd<0)
	{
	    perror("cannot create listening socket");
		return 1;
	}


	memset(&srv_addr,0,sizeof(srv_addr));
	//填充伺服器資訊 
	srv_addr.sin_family=AF_INET;
	srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	srv_addr.sin_port=htons(port);


	//將伺服器和套節字繫結
	ret=bind(listen_fd,(struct sockaddr *)&srv_addr,sizeof(srv_addr));
	if(ret==-1)
	{
	    perror("cannot bind server socket");
		close(listen_fd);
		return 1;
	}

	//設定連線5個客戶端
	ret=listen(listen_fd,5);
	if(ret==-1)
	{
	    perror("cannot listen the client connect request");
		close(listen_fd);
		return 1;
	}

	//對每個連線來的客戶端建立一個執行緒,單獨與其進行通訊 ,首先呼叫read函式讀取客戶端傳送來的資訊 
	while(1)
	{
	    len=sizeof(clt_addr);
		com_fd=accept(listen_fd,(struct sockaddr *)&clt_addr,&len);
		if(com_fd<0)
		{
		    if(errno==EINTR)
			{
			    continue;
			}
			else
			{
			    perror("cannot accept client connect request");
				close(listen_fd);
				return 1;
			}
		}
		if((pthread_create(&tid,NULL,thr_fn,&com_fd))==-1)//多執行緒呼叫 ,跳到thr_fn函式 
		{
		    perror("pthread_create error");
			close(listen_fd);
			close(com_fd);
			return 1;
		}
	}
	return 0;
}