C语言网络通信编程
网络编程的基本概念:
1. 基本结构
struct sockaddr{
unsigned short sa_family;
char sa_data[14];
};
struct sockaddr_in{
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
struct in_addr{
unsiged long s_addr;
};
说明:sockaddr结构是用于函数参数使用的,sockaddr_in 其实内部数据和sockaddr结构一样,只不过定义不一样,定义sockaddr_in结构只是为了编程是填入地址族,ip地址和端口方便,在调用套接字函数时,需要强制类型转换为sockaddr。为什么这么做,估计是sockaddr结构定义的比较早,所以不忍丢弃。
2. 基本转换函数
*网络字节顺序:网络采用大尾方式,inter386采用小尾方式
*网络数字转换
htos host to network short
hotl host to network long
ntos network to host short
ntol network to host long*网络地址转换
inet_addr() 将字符串型IP地址转换为无符号long int
inet_ntoa() 将IP地址数字转换为字符串
3. 基本套接字函数
这里只说其中几个比较重要的函数
socket(ip_family,data_type,protocol);
bind(socket, struct sockaddr, len);
指定一个本地的端口用来进行通信,使用本地ip和port填充结构connect(socket,struct sockaddr,len);
任意指定一个未用端口,内部调用bind进行绑定,使用远程ip和port填充结构listen(socket,backlog);
backlog 未经处理的连接请求队列中可以容纳的最大数目。
accept(listen_socket,out struct sockaddr,len);
accept拿出listen函数放入等待队列中的第一条消息进行处理,然后返回这个消息的管理套接字。
注意:在服务器端,函数listen会将在客户端函数connect发来的请求排成队列,然后交由accept来处理,因此函数accept返回客户端通信套接字,并返回客户端的ip地址,通信端口等信息;在客户端,connect函数在内部任意指定一个未用端口,然后绑定,用于和服务器端通信。
accept如果接不到请求,会阻塞。
accept如果接到请求,TCP的3次握手过程已完成,后面就可以用send和recv函数发送和接受数据。
4. 代码示例
客户端代码:
#include
#include
#include#pragma comment(lib,"ws2_32.lib")
int main()
{
WSADATA WSData;
SOCKET ConnectSocket;if (WSAStartup(MAKEWORD(2,2),&WSData) != 0)
{
printf("socket initial error ! ");
return 1;
}ConnectSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (ConnectSocket == SOCKET_ERROR)
{
printf("create socket error! ");
WSACleanup();
return 1;
}
sockaddr_in Client;
Client.sin_family = AF_INET;
Client.sin_addr.s_addr = inet_addr("192.168.8.21");
Client.sin_port = htons(4600);// connect to server
if (connect(ConnectSocket,(sockaddr*)&Client,sizeof(Client)) != 0)
{
printf("connect error! ");
return 1;
}
// translate data
char SendBuf[100] = "hi";
send(ConnectSocket,SendBuf,lstrlenA(SendBuf)+1,0);char RecvBuf[101];
recv(ConnectSocket,RecvBuf,lstrlenA(RecvBuf)+1,0);
printf("%s ",RecvBuf);// close socket
closesocket(ConnectSocket);
WSACleanup();
return 0;
}服务器端代码:
#include
#include
#include#pragma comment(lib,"ws2_32.lib")
int main()
{
WSADATA wsaData;
SOCKET ListenSocket;int iResult;
// 初始化socket
iResult = WSAStartup(MAKEWORD(2,2),&wsaData);
if(iResult != 0)
{
printf("WSAStartup failed:%d ",iResult);
return 1;
}
// 创建socket
ListenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET)
{
printf("Error at socket():%d ",WSAGetLastError());
WSACleanup();
return 1;
}
// band socket
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("192.168.8.21");
service.sin_port = htons(4600);if (bind(ListenSocket,(sockaddr*)&service,sizeof(service)) == SOCKET_ERROR)
{
printf("bind() failed. ");
closesocket(ListenSocket);
return 1;
}// listen socket
if (listen(ListenSocket,SOMAXCONN) == SOCKET_ERROR)
{
printf("listen() failed. ");
closesocket(ListenSocket);
return 1;
}// accept a socket and use it recv or send
sockaddr_in Client;
SOCKET ConnectSocket;
int len = sizeof(sockaddr_in);
while (1)
{
ConnectSocket= accept(ListenSocket,(sockaddr*)&Client,&len);char RecvBuf[100];
recv(ConnectSocket,RecvBuf,lstrlenA(RecvBuf)+1,0);
printf("%s ",RecvBuf);char SendBuf[100] = "hello man !";
send(ConnectSocket,SendBuf,lstrlenA(SendBuf)+1,0);
}// close socket
closesocket(ConnectSocket);
closesocket(ListenSocket);
WSACleanup();
return 0;
}
补充:软件开发 , C语言 ,