简单的TCP回射服务程序与客户程序(修改自UNP一书)

原创 2012年03月30日 01:16:11
#ifndef INITSOCK_H_
/*	---------------------------------------------------
	文件:InitSock.h
	功能简述:载入winsock库


	---------------------------------------------------	*/


#define INITSOCK_H_

#include<windows.h>
#include<cstdio>
#include<process.h>

class CInitSock
{
public :
	CInitSock(BYTE MinorVer = 2  , BYTE MajorVer = 2)
	{
		WORD SocketVersion = MAKEWORD(MinorVer,MajorVer) ;
		
		if(WSAStartup(SocketVersion,&wsaData) != 0 )
		{
			printf("加载Winsock库失败\n") ;
			exit(0) ;
		}
	}
	
	~CInitSock()
	{
		WSACleanup() ;
	}

private :
	WSADATA wsaData ;
} ;



typedef unsigned (_stdcall *PTHREAD_START) (void *) ;

#define chBEGINTHREADEX(psa,cbStackSize,pfnStartAddr,	\
			pvParam,fdwCreateFlags,pdwThreadID)			\
		((HANDLE) _beginthreadex(					\
			(void*)(psa),							\
			(unsigned)(cbStackSize),				\
			(PTHREAD_START)(pfnStartAddr),			\
			(void *)(pvParam),						\
			(unsigned)(fdwCreateFlags),				\
			(unsigned *)(pdwThreadID)))				

#endif 

 

/*	-------------------------------
	文件:tcpserver.cpp
	  
	TCP回射服务程序:
	  
	经验:

	1.如果客户端主动关闭,则可以看到客户端TCP状态转换,由FIN_WAIT1
	  到TIME_WAIT。
	2.如果服务端主动关闭,用netstat观察TCP状态,没有见到任何状态
	  转换,初步估计是因为服务端和客户端运行在同一台主机上面的,在很
	  短的时间内,很快完成了4次握手的过程,所以我看不见.
	3.在beginthreadex之后不能马上调用closesocket来关闭内核对象。因为
	  在创建新线程的时候,它的引用计数没有增加。所以如果用closesocket的话
	  就会使套接字变为无效的套接字。内核对象的继承应该是在进程之间。
	4.在客户端主动退出之后,服务端也要关闭相应诉套接字,这样服务端的状态
	  才会从closewait离开
	5.用beginthreadex开新线程的时候,线程参数的传递用的是指针传递,所以不
	  用想得太复杂,直接用传地址。然后在线程函数内强制转型即可。
	6.网络状态可以用netstat ,ipconfig之类的工具来查看,虽然没有Linux
	  下那些那么强大.
    7.如果服务端被强制退出,客户发送数据将会收到复位错误。
	-------------------------------	*/


#include<winsock2.h>
#include"InitSock.h"
#include<windows.h>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<process.h>



#pragma comment(lib,"ws2_32.lib")

#define SEVER_PROT 5010
#define MAXLINE 1024

DWORD WINAPI str_echo(PVOID pvParam) ;

CInitSock InitSock ;

int main(void)
{
	SOCKET sListenfd , sConnectfd ;	
	int iClilen = 0 ;
	DWORD dwThreadId = 0 ;
	sockaddr_in Cliaddr , Servaddr ;
	DWORD dwError = 0 ;
	HLOCAL hHlocal = NULL ;
	HANDLE	hThread = NULL ;

	sListenfd = socket(AF_INET,SOCK_STREAM,0) ;

	memset(&Servaddr,0,sizeof(Servaddr)) ;
	memset(&Cliaddr,0,sizeof(Cliaddr)) ;

	Servaddr.sin_family = AF_INET ;
	Servaddr.sin_port = htons(SEVER_PROT) ;
	Servaddr.sin_addr.s_addr = htonl(INADDR_ANY) ;

	if(SOCKET_ERROR == bind(sListenfd,(SOCKADDR *)&Servaddr,sizeof(Servaddr)))
	{
		dwError = WSAGetLastError() ;
		printf("绑定错误,错误代码为: %d\n",dwError) ;
		return -1 ;
	}

	if(SOCKET_ERROR == listen(sListenfd,5))
	{
		dwError = WSAGetLastError() ;
		printf("监听错误,错误代码为 : %d\n",dwError) ;
		return -1 ;
	}
	
	for( ; ; )
	{
		iClilen = sizeof(Cliaddr) ;
	
		printf("等待一个新连接....\n") ;
		sConnectfd = accept(sListenfd,(SOCKADDR *)&Cliaddr,&iClilen) ;

		if(SOCKET_ERROR == sConnectfd)
		{
			dwError = WSAGetLastError() ;
			printf("连接错误,错误代码为 : %d\n",dwError) ;

			closesocket(sConnectfd)  ;
			continue ;
		}
		else
		{
			hThread = chBEGINTHREADEX(NULL,0,str_echo,(PVOID)&sConnectfd,0,&dwThreadId) ;
//			closesocket(sConnectfd) ;								//为什么不能减少他的引用计数呢 ?
			CloseHandle(hThread) ;
		}

	}	

	closesocket(sListenfd) ;

	return 0 ;
}


DWORD WINAPI str_echo(PVOID pvParam)
{
	SOCKET  sConnfd = *((SOCKET *)pvParam) ;		//这里转型....
		
	int n = 0 ;  //改为int 就不会死循环了,因为下面可以返回-1
	TCHAR szBuf[MAXLINE] ;

	while((n = recv(sConnfd,szBuf,sizeof(szBuf),0)) > 0 )		//客户端突然退出会发生死循环
	{
		szBuf[n] = '\0' ;
		printf("套接口 %d : 接收到 %u 字节的数据,内容为:%s\n",sConnfd,n,szBuf) ;
		send(sConnfd,szBuf,n,0) ;
	}

	closesocket(sConnfd) ;						//如果不加这一句的话,就会造成半关闭,服务器一直
												//停留在CLOSE_WAIT

	return 0 ;
}

 

/*	--------------------------------------------------------------
	文件:tcpclient.cpp

	简单的TCP回射客户程序

	经验:回车符也被当作一个字符来发送

	--------------------------------------------------------------	*/
#include<winsock2.h>
#include"InitSock.h"
#include<windows.h>
#include<cstdio>
#include<cstdlib>
#include<cstring>

#pragma comment(lib,"ws2_32.lib")

#define SERVER_PORT  5010
#define MAXLINE	1024

void str_cli(FILE *fp , SOCKET sockfd) ;


CInitSock InitSock ;

int main(void)
{
	SOCKET sConnfd ;
	sockaddr_in	Servaddr ;
	DWORD dwError = 0 ;

	memset(&Servaddr,0,sizeof(Servaddr)) ;
	
	sConnfd = socket(AF_INET,SOCK_STREAM,0) ;

	Servaddr.sin_family = AF_INET ;
	Servaddr.sin_port = htons(SERVER_PORT) ;
	Servaddr.sin_addr.s_addr = inet_addr("127.0.0.1") ;


	if(SOCKET_ERROR == connect(sConnfd,(SOCKADDR *)&Servaddr,sizeof(Servaddr)) )
	{
		dwError = WSAGetLastError() ;
		printf("连接出错,错误代码: %d\n",dwError) ;
		return -1 ;
	}

	str_cli(stdin,sConnfd) ;

	closesocket(sConnfd) ;

	return 0 ;
}

void str_cli(FILE *fp , SOCKET sockfd) 
{
	TCHAR szSendLine[MAXLINE] ;
	TCHAR szRecvLine[MAXLINE] ;
	int nRecv = 0;

	while(fgets(szSendLine,MAXLINE,fp) != NULL)
	{
		szSendLine[strlen(szSendLine)] = '\0' ;
		nRecv = send(sockfd,szSendLine,strlen(szSendLine),0) ; 		//最后一个字符是回车符
		if((nRecv = recv(sockfd,szRecvLine,MAXLINE,0)) == 0)
		{
			puts("程序退出.") ;
			return  ;
		}	
		
		szRecvLine[nRecv] = '\0' ;

		fputs(szRecvLine,stdout) ;
	}

}



 


 

简单的UDP回射服务程序与客户程序(修改自Unix网络编程一书)

#include #include"InitSock.h" #include #include #include #include #pragma comment(lib,"...
  • gzzheyi
  • gzzheyi
  • 2012年03月30日 01:18
  • 822

TCP多进程并发编程-回射服务/客户程序

TCP学习之建立一个简单的客户/服务器系统--回射系统 相关的资料可以参考Unix网络编程,这个只是修改版,不需要依赖任何文件,可以独立编译通过,而且是在两台不同的主机上进行的。 fgge...

Pro_6_UNIX下TCP回射服务与客户程序优化版_2016_08_17

当子进程结束的时候,内核会发送SIGCHLD信号给它的父进程。父进程会根据这个SIGCHLD来回收进程的资源。当父进程不回收资源的时候,就会产生僵尸进程。这显然不符合我们的编程规范,因为僵尸进程会占用...
  • kao2406
  • kao2406
  • 2016年08月18日 00:03
  • 229

Pro_5_UNIX下TCP回射服务与客户程序_2016_08_15

这里回射的意思类似于linux下的回显命令,当我们在控制台下echo hello的时候,屏幕就会显示hello。回射也是这个意思,当我们运行程序后在控制台下输入一串字符串回车,则显示该字符串。 ...
  • kao2406
  • kao2406
  • 2016年08月15日 23:21
  • 145

UNIX网络编程学习(11)--分析TCP回射服务+客户程序:正常启动与正常终止

分析TCP回射服务+客户程序: 启动服务器程序后,netstat -a,后终端出现: Active Internet connections (servers and established) ...

第五章 TCP回射客户程序

本章大意 讲解了一个回射C/S程序,并分析各种情况下执行的情况。 细节摘录 1. 服务器程序代码初步分析: #include "unp.h" int main(int argc, char **a...

VC++ TCP/IP 服务/客户程序源代码

//TCP //服务器端程序 #include #include #include #include #include #pragma comment( lib, "ws2_32.lib" ) #...
  • ypist
  • ypist
  • 2012年10月25日 19:12
  • 2181

UNIX网络编程(10)--TCP 回射服务器程序和客户程序

一个简单的回射服务器的步骤: 1.客户端从标准输入读入一行文本,并写给服务器。 2.服务器端从网络输入读入这行文本,并返回给客户 3.客户端从网络输入读入这行反射文本,并显示在标准输出上。 如...

TCP服务客户程序设计.

  • 2014年03月30日 15:48
  • 101KB
  • 下载

tcp_client.c 客户程序服务模型

#include #include #include #include #include #include #include #include #define port...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:简单的TCP回射服务程序与客户程序(修改自UNP一书)
举报原因:
原因补充:

(最多只允许输入30个字)