C语言 粗体字公共部分 斜体字为服务器 其余为客户端
服务器客户端
#include
#include
#pragma comment(lib,"WS2_32.lib")
int main(int argc, char* argv[])
{
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2,0);//指定版本号,使用WINSOCK2版本
::WSAStartup(sockVersion, &wsaData);//载入winsock的dll启动函数
第一个参数是WINSOCK版本号,第二个参数是指向WSADATA的指针
SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//创建套接字基于TCP,第一个是协议域,AF_IMET决定了要用IPV4地址(32位)与端口号(16位)的组合,把ipv4地址和端口号组合赋给socket;第二个指定socket的类型;第三个指定协议,此处对应TCP传输协议,简单来说既是(使用TCP/IP协议;传输过程使用TCP;不适用其他特殊协议)
if(s == INVALID_SOCKET)
{
printf("error");
::WSACleanup();
//终止函数,清理,释放资源应用程序在完成对请求的socket库的使用后WSAClanup,
清除套接字资
函数来接触与socket库的绑定并且释放socket库所占用的系统资源
return 0;
}
sockaddr_in sin;//socket中装入地址信息
sockaddr_in servAddr;//定义套接字地址
sin.sin_family = AF_INET;//sin.family表示地址族,对于IP地址,sin_family将一直是AF_INET
servAddr.sin_family = AF_INET;//储存IP地址,INADDR_ANY就是制定地址为0.0.0.0的地址,
这个地址事实上表示不确定地址,或“所有地址”、“任意地址”
sin.sin_port = htons(8888);//端口号表示服务器监听的端口号使8888
servAddr.sin_port = htons(8888);//端口号表示客户端接受服务器8888端口号
sin.sin_addr.S_un.S_addr = INADDR_ANY;//储存地址,INADDR就是指定地址为
0.0.0.0的地址,这个地址事实上表示不确定地址,也就是所有的地址或任意地址
servAddr.sin_addr.S_un.S_addr = inet_addr("192.168.31.220");//本地IP地址,
inet_addr()将IP地址转为点分十进制的格式
//绑定socket,绑定地址及端口号
if(::bind(s, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
参数一:指定与那个套接字绑定
参数二:指定地址
参数三:确定恢复多少数据
{
printf("error");
::WSACleanup();//清理释放资源
return 0;
}
//bind函数把一个地址族中的特定地址赋给socket。第一个参数是socket描述字,通过socket创建,唯一标识一个socket。bind()函数就是将这个表述字绑定一个名字。第二个参数指向要绑定给socket的协议地址。第三个参数对应的是地址的长度。
为服务器端定义的这个监听的socket指定一个地址及端口(port),这样客户端才知道待会儿要
连接哪一个地址的哪个端口,为此我们要调用bind函数
//监听socket,监听客户端的连接请求
if(::listen(s, 2) == SOCKET_ERROR)//监听客户端请求
参数一:被listen函数调用的套接字
参数二:连接数量的上限
{
printf("error");
::WSACleanup();//释放资源
return 0;
}
//连接主动完成连接过程,三次握手协议,谁调用了connet函数谁就是先发送数据的一方
if(::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)//连接服务器
参数一:指定数据发送的套接字
参数二:指定数据发送的目的地址,也就是服务端地址
{
printf("error");
::WSACleanup(); //释放资源
return 0;
}
char buff[156];//缓冲区
int nRecv = ::recv(s, buff, 156, 0);//接收数据并打印到屏幕上
//不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。
第一个参数:指定接收端套接字描述符
第二个参数:指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据
第三个参数:指明buf的长度
第四个参数:一般设置0
if(nRecv > 0)
{
buff[nRecv] = '\0';
printf("接受数据:%s",buff);
}
sockaddr_in remoteAddr;
int nAddrLen = sizeof(remoteAddr);
SOCKET client;
char szText[] = "peter\n";//缓冲区数据
while(1)循环接受连接请求
{accept默认会阻塞进程,直到有一个客户建立连接后返回,他返回的是一个新
可用的套接字,这个套接字是连接套接字
/*accept服务器端使用,调用函数进入阻塞状态,等待用户连接,如果没有客户端进行连接,程序就在这个地方。
不会看到后面。如果有客户端连接,那么程序就执行一次然后继续循环到这里等待。*/
client = ::accept(s, (SOCKADDR*)&remoteAddr, &nAddrLen);
参数一:监听套接字,这个套接字用来监听一个端口,当有一个客户与服务器连接时,它使用这个端口号,而此时这个端口号正与这个套接字关联。当然客户不知道套接字这些细节,他只知道一个地址和一个端口号
参数二:这是一个结果参数,它用来接受一个返回值,这返回值指定客户端的地址。
//acc
if(client == INVALID_SOCKET)
{
printf("error");
continue;
}
printf("接受到一个连接:%s\r\n",inet_ntoa(remoteAddr.sin_addr));客户端IP
::send(client, szText, strlen(szText), 0); //发送数据,发送本地时间给客户端
//不论是客户还是服务器应用程序都用send函数来想TCP连接的另一端发送数据,
客户程序一般都用send函数向服务器发送请求,而服务器则通常用send函数
来向客户程序发送应答。
第一个参数:指定发送端套接字描述符
第二个参数指明一个存放应用程序要发送数据的缓冲区
第三个参数指明实际要发送的数据的字节数
第四个参数一般设置0
::closesocket(client);//关闭套接字,关闭连接
}
::closesocket(s);关闭套接字
::WSACleanup();
return 0;
}
2015.7.7