简单的TCP回射服务程序与客户程序(修改自UNP一书)
2012-03-30 01:16
405 查看
#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 = '\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网络编程一书)
- 一个简单的linux下原生socket的tcp程序及其修改
- tcp_client.c 客户程序服务模型
- Pro_5_UNIX下TCP回射服务与客户程序_2016_08_15
- VC++ TCP/IP 服务/客户程序源代码
- 一个简单的tcp服务程序
- java简单的TCP服务程序
- 读书笔记之 简单时间获取客户/服务程序
- java简单的TCP服务程序
- 简单进程池实现多TCP客户服务
- 简单的Linux环境下多线程TCP服务程序框架
- VC++ TCP/IP 服务/客户程序源代码
- 简单的Linux环境下多线程TCP服务程序框架
- Pro_6_UNIX下TCP回射服务与客户程序优化版_2016_08_17
- TCP多进程并发编程-回射服务/客户程序
- VC++ TCP/IP 服务/客户程序源代码
- UNIX网络编程学习(11)--分析TCP回射服务+客户程序:正常启动与正常终止
- 用 C++ 创建简单的 Win32 服务程序
- TCP本地通信 简单程序实现 (一)
- 用C#写一个简单的WINDOWS服务程序