作者在 2009-03-16 11:29:46 发布以下内容
我改写了MSDN上的代码。作为socket之间通信的例子
可以看到这是一个阻塞式的通信过程。
“127.0.0.1”这个IP是内部回环测试的IP号。
代码涉及以下几个socket 常用的api 函数。
WSAStartup
socket
bind
accept
recv
send
WSACleanup
//下面是服务器的代码.程序使用的是TCP协议通信
//在库中加入 wsock32.lib
#include <stdio.h>
#include "winsock2.h"//这是一个SOCKET的头文件
#include "winsock2.h"//这是一个SOCKET的头文件
void main()
{
//----------------------
// Initialize Winsock.
char getbuf[1024];
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);//这个函数是初始化socket版本的函数,一定要用
if (iResult != NO_ERROR)
printf("Error at WSAStartup()\n");
{
//----------------------
// Initialize Winsock.
char getbuf[1024];
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);//这个函数是初始化socket版本的函数,一定要用
if (iResult != NO_ERROR)
printf("Error at WSAStartup()\n");
//----------------------
// Create a SOCKET for listening for
// incoming connection requests.
SOCKET ListenSocket;
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//这里初始化了socket的通信方式为流式
if (ListenSocket == INVALID_SOCKET)
{
printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return;
}
// Create a SOCKET for listening for
// incoming connection requests.
SOCKET ListenSocket;
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//这里初始化了socket的通信方式为流式
if (ListenSocket == INVALID_SOCKET)
{
printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(27015);
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(27015);
if (bind( ListenSocket,
(SOCKADDR*) &service,
sizeof(service)) == SOCKET_ERROR)
{
printf("bind() failed.\n");
closesocket(ListenSocket);
return;
}
(SOCKADDR*) &service,
sizeof(service)) == SOCKET_ERROR)
{
printf("bind() failed.\n");
closesocket(ListenSocket);
return;
}
//----------------------
// Listen for incoming connection requests.
// on the created socket
if (listen( ListenSocket, 1 ) == SOCKET_ERROR)
printf("Error listening on socket.\n");
// Listen for incoming connection requests.
// on the created socket
if (listen( ListenSocket, 1 ) == SOCKET_ERROR)
printf("Error listening on socket.\n");
//----------------------
// Create a SOCKET for accepting incoming requests.
SOCKET AcceptSocket;
printf("Waiting for client to connect...\n");
// Create a SOCKET for accepting incoming requests.
SOCKET AcceptSocket;
printf("Waiting for client to connect...\n");
//----------------------
// Accept the connection.
while(1)
{
AcceptSocket = SOCKET_ERROR;
while( AcceptSocket == SOCKET_ERROR )
{
AcceptSocket = accept( ListenSocket, NULL, NULL );
}
printf("Client connected.\n");
//ListenSocket = AcceptSocket;
break;
}
int bytesrecv;
int bytesSent;
char m_ack[4]="ACK";
while(1)
{
bytesrecv=recv(AcceptSocket,getbuf,1024,0);//流式使用recv接收数据
if(bytesrecv!=-1)
{
if(bytesrecv<=1024)
getbuf[bytesrecv]='\0';
printf("%s\n",getbuf);
bytesSent = send( AcceptSocket, m_ack, strlen(m_ack), 0 );//流式使用send发送数据
}
if(bytesrecv==SOCKET_ERROR)
{
printf("Client close.\n");
break;
}
}
system("pause");
WSACleanup();
return;
}
/*
以下是客户端代码
同样记得在库中加入 wsock32.lib
*/
#include <stdio.h>
#include <conio.h>
#include "winsock2.h"
void main()
{
//----------------------
// Initialize Winsock
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR)
{
printf("Error at WSAStartup()\n");
system("pause");
return;
}
//----------------------
// Create a SOCKET for connecting to server
SOCKET ConnectSocket;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET)
{
printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
system("pause");
return;
}
{
//----------------------
// Initialize Winsock
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR)
{
printf("Error at WSAStartup()\n");
system("pause");
return;
}
//----------------------
// Create a SOCKET for connecting to server
SOCKET ConnectSocket;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET)
{
printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
system("pause");
return;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port of the server to be connected to.
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
clientService.sin_port = htons( 27015 );
// The sockaddr_in structure specifies the address family,
// IP address, and port of the server to be connected to.
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
clientService.sin_port = htons( 27015 );
//----------------------
// Connect to server.
if ( connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR)
{
printf( "Failed to connect.\n" );
WSACleanup();
system("pause");
return;
}
//----------------------
// Declare and initialize variables.
int bytesSent;
int bytesRecv = SOCKET_ERROR;
char sendbuf[1024] = "Client: Sending data.";
char recvbuf[1024] = "";
// Connect to server.
if ( connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR)
{
printf( "Failed to connect.\n" );
WSACleanup();
system("pause");
return;
}
//----------------------
// Declare and initialize variables.
int bytesSent;
int bytesRecv = SOCKET_ERROR;
char sendbuf[1024] = "Client: Sending data.";
char recvbuf[1024] = "";
//----------------------
printf("connect ok!\n");
bytesSent = send( ConnectSocket, sendbuf, strlen(sendbuf), 0 );
bytesRecv = recv( ConnectSocket, recvbuf, 32, 0 );
int putin=0;
char inchar;
while(bytesRecv!=SOCKET_ERROR)
{
if ( bytesRecv == -1 || bytesRecv == WSAECONNRESET )
{
printf( "Connection Closed.\n");
break;
}
putin=0;
while(1)
{
inchar=getch();
if(inchar==13)
{
printf("\n");
break;
}
else
{
sendbuf[putin++]=inchar;
putch(inchar);
}
}
sendbuf[putin]='\0';
bytesSent = send( ConnectSocket, sendbuf, strlen(sendbuf), 0 );
bytesRecv = recv( ConnectSocket, recvbuf, 1024, 0 );
if(bytesRecv==-1)
{
printf("server close\n");
break;
}
}
printf("connect ok!\n");
bytesSent = send( ConnectSocket, sendbuf, strlen(sendbuf), 0 );
bytesRecv = recv( ConnectSocket, recvbuf, 32, 0 );
int putin=0;
char inchar;
while(bytesRecv!=SOCKET_ERROR)
{
if ( bytesRecv == -1 || bytesRecv == WSAECONNRESET )
{
printf( "Connection Closed.\n");
break;
}
putin=0;
while(1)
{
inchar=getch();
if(inchar==13)
{
printf("\n");
break;
}
else
{
sendbuf[putin++]=inchar;
putch(inchar);
}
}
sendbuf[putin]='\0';
bytesSent = send( ConnectSocket, sendbuf, strlen(sendbuf), 0 );
bytesRecv = recv( ConnectSocket, recvbuf, 1024, 0 );
if(bytesRecv==-1)
{
printf("server close\n");
break;
}
}
system("pause");
WSACleanup();
WSACleanup();
return;
}
}
注:先运行服务器端程序,再运行客户端程序。这样就完成了连接。在客户端程序输入字符回车后数据发到服务器程序。服务器程序显示客户端发送数据。
以下是使用UDP数据报的连接方式。
服务器程序:
同样记得在库中加入 wsock32.lib
#include <stdio.h>
#include "winsock2.h"
#include "winsock2.h"
void main() {
WSADATA wsaData;
SOCKET RecvSocket;
sockaddr_in RecvAddr;
int Port = 27015;
char RecvBuf[1024];
int BufLen = 1024;
sockaddr_in SenderAddr;
int SenderAddrSize = sizeof(SenderAddr);
SOCKET RecvSocket;
sockaddr_in RecvAddr;
int Port = 27015;
char RecvBuf[1024];
int BufLen = 1024;
sockaddr_in SenderAddr;
int SenderAddrSize = sizeof(SenderAddr);
//-----------------------------------------------
// Initialize Winsock
WSAStartup(MAKEWORD(2,2), &wsaData);
// Initialize Winsock
WSAStartup(MAKEWORD(2,2), &wsaData);
//-----------------------------------------------
// Create a receiver socket to receive datagrams
RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// Create a receiver socket to receive datagrams
RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//-----------------------------------------------
// Bind the socket to any address and the specified port.
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// Bind the socket to any address and the specified port.
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(RecvSocket, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr));
//-----------------------------------------------
// Call the recvfrom function to receive datagrams
// on the bound socket.
printf("Receiving datagrams...\n");
while(1)
{
recvfrom(RecvSocket,
RecvBuf,
BufLen,
0,
(SOCKADDR *)&SenderAddr,
&SenderAddrSize);
printf("%s\n",RecvBuf);
}
//-----------------------------------------------
// Close the socket when finished receiving datagrams
printf("Finished receiving. Closing socket.\n");
closesocket(RecvSocket);
// Call the recvfrom function to receive datagrams
// on the bound socket.
printf("Receiving datagrams...\n");
while(1)
{
recvfrom(RecvSocket,
RecvBuf,
BufLen,
0,
(SOCKADDR *)&SenderAddr,
&SenderAddrSize);
printf("%s\n",RecvBuf);
}
//-----------------------------------------------
// Close the socket when finished receiving datagrams
printf("Finished receiving. Closing socket.\n");
closesocket(RecvSocket);
//-----------------------------------------------
// Clean up and exit.
printf("Exiting.\n");
WSACleanup();
return;
}
// Clean up and exit.
printf("Exiting.\n");
WSACleanup();
return;
}
以下是客户端代码。
同样记得在库中加入 wsock32.lib
#include <stdio.h>
#include <conio.h>
#include "winsock2.h"
#include <conio.h>
#include "winsock2.h"
void main()
{
WSADATA wsaData;
SOCKET SendSocket;
sockaddr_in RecvAddr;
int Port = 27015;
char SendBuf[1024];
int BufLen = 1024;
{
WSADATA wsaData;
SOCKET SendSocket;
sockaddr_in RecvAddr;
int Port = 27015;
char SendBuf[1024];
int BufLen = 1024;
//---------------------------------------------
// Initialize Winsock
WSAStartup(MAKEWORD(2,2), &wsaData);
// Initialize Winsock
WSAStartup(MAKEWORD(2,2), &wsaData);
//---------------------------------------------
// Create a socket for sending data
SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// Create a socket for sending data
SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//---------------------------------------------
// Set up the RecvAddr structure with the IP address of
// the receiver (in this example case "123.456.789.1")
// and the specified port number.
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
RecvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
// Set up the RecvAddr structure with the IP address of
// the receiver (in this example case "123.456.789.1")
// and the specified port number.
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
RecvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
//---------------------------------------------
// Send a datagram to the receiver
printf("Sending a datagram to the receiver...\n");
int inchar=0;
int inlen=0;
while(1)
{
inlen=0;
while(inchar!=13)
{
inchar=getch();
if(inchar==27)
{
printf("Exiting.\n");
WSACleanup();
return;
}
SendBuf[inlen++]=inchar;
printf("%c",inchar);
}
printf("\n");
SendBuf[inlen]='\0';
inchar='\0';
sendto(SendSocket,
SendBuf,
BufLen,
0,
(SOCKADDR *) &RecvAddr,
sizeof(RecvAddr));
}
//---------------------------------------------
// When the application is finished sending, close the socket.
printf("Finished sending. Closing socket.\n");
closesocket(SendSocket);
// Send a datagram to the receiver
printf("Sending a datagram to the receiver...\n");
int inchar=0;
int inlen=0;
while(1)
{
inlen=0;
while(inchar!=13)
{
inchar=getch();
if(inchar==27)
{
printf("Exiting.\n");
WSACleanup();
return;
}
SendBuf[inlen++]=inchar;
printf("%c",inchar);
}
printf("\n");
SendBuf[inlen]='\0';
inchar='\0';
sendto(SendSocket,
SendBuf,
BufLen,
0,
(SOCKADDR *) &RecvAddr,
sizeof(RecvAddr));
}
//---------------------------------------------
// When the application is finished sending, close the socket.
printf("Finished sending. Closing socket.\n");
closesocket(SendSocket);
//---------------------------------------------
// Clean up and quit.
printf("Exiting.\n");
WSACleanup();
return;
}
// Clean up and quit.
printf("Exiting.\n");
WSACleanup();
return;
}
socket的内回环也可以作为进程间通信的方式。以上代码可以看出socket通信是使用阻塞方式的(在服务器的recvfrom处做个中断就可以看出来了。程序会停留在那里等待接收数据)在win32或linux下可以使用多线程来实现非阻塞通信。