c/c++多线程编程(客户端,服务端半双工实现)

简介 了解了Socket 通信的原理,在此基础上编写一个聊天程序。

客户端实现:

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

//客户端代码
int  main()

{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return 0;
}

if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( );
return 0;
}
SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
printf("连接服务器\n");
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

int flag=1;
char sendBuff[50];
char recvBuf[50];
while(flag==1){
scanf("%s",sendBuff);
send(sockClient,sendBuff,50,0);
printf("我:%s\n",sendBuff);
recv(sockClient,recvBuf,50,0);
printf("%s\n",recvBuf);
}
closesocket(sockClient);
WSACleanup();

}

服务器实现代码:

#include
#include
#pragma comment(lib,"ws2_32.lib")
//服务端代码
/****

WORD DWORD BYTE相互转换:
DWORD 4个字节
WORD 2个字节
BYTE 1个字节
***/
int  main()
{
/***word (编程语言中的一种数据类型) 编辑WORD是无符号的短整型,且占2个字节*/
WORD wVersionRequested;

WSADATA wsaData;
//定义错误
int err;
/**MAKEWORD 宏 平台:SDK这个宏创建一个无符号16位整型,
通过连接两个给定的无符号参数。
(注:typedef unsigned short WORD;)*/
wVersionRequested = MAKEWORD( 1, 1 );

/***
WSAStartup,即WSA(Windows Sockets Asynchronous,Windows异步套接字)的启动命令。
是Windows下的网络编程接口软件Winsock1
或 Winsock2 里面的一个命令(Ps:Winsock 是由Unix下的BSD Socket发展而来,
是一个与网络协议无关的编程接口)。
***/
err = WSAStartup( wVersionRequested, &wsaData );
//0 成功
//是否错误
if ( err != 0 ) {
return 0;
}
//检测错误
if (LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( );

return 0;

}
//定义一个套接字
/***
SOCK_STREAM Tcp连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输
AF_INET(又称 PF_INET)是 IPv4 网络协议的套接字类型,AF_INET6 则是 IPv6 的;而 AF_UNIX 则是 Unix 系统本地通信。
**/
SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);
/***
SOCKADDR_IN 编辑
在windows/linux下有下面结构:
sockaddr结构
struct sockaddr
{
unsigned short sa_family;   addressfamily,AF_xxx
char sa_data[14];  14bytesofprotocoladdress
};
**/
/***
struct sockaddr_in

{

short sin_family;/*Address family一般来说AF_INET(地址族)PF_INET(协议族)

unsigned short sin_port;/*Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)

struct in_addr sin_addr;/*IP address in network byte order(Internet address)

unsigned char sin_zero[8];/*Same size as struct sockaddr没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐

};
**/
SOCKADDR_IN addrSrv;

addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

addrSrv.sin_family=AF_INET;

addrSrv.sin_port=htons(6000);

bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

listen(sockSrv,5);

SOCKADDR_IN addrClient;

int len=sizeof(SOCKADDR);
int flag=1;
SOCKET sockConn;
if(flag==1){
printf("正在接受连接\n");
sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
printf("连接成功\n");
}
//定义发送缓冲区
char sendBuf[50];
//接收缓冲区
char recvBuf[50];
while(flag==1){
scanf("%s",sendBuf);
//sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(addrClient.sin_addr));
send(sockConn,sendBuf,strlen(sendBuf)+1,0);
printf("我说:%s\n",sendBuf);
recv(sockConn,recvBuf,50,0);
printf("客户端说:%s\n",recvBuf);

//recv()是编程语言函数。recv先等待s的发送缓冲中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR;

//flag=0;
}

closesocket(sockConn);
return 0;
}


代码比较简单,效果如图:



文章评论

Top