一、面向连接的TCP流模式
二、server程序
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
/* socket
* bind
* listen
* accept
* send/recv
*/
#define SERVER_PORT 8888 // Server端口
#define BACKLOG 10 // listen请求排队的最大长度
int main(int argc, char **argv)
{
int iSocketServer;
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
struct sockaddr_in tSocketClientAddr;
int iRet;
int iAddrLen;
int iRecvLen;
int iClientNum = -1;
unsigned char ucRecvBuf[1000];
signal(SIGCHLD,SIG_IGN); // 避免僵死子进程
/* 1.创建Server端套接字,AF_INET表明地址族 IPv4 Internet,SOCK_DGRAM表明使用 UDP 协议,返回文件描述符。 */
iSocketServer = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == iSocketServer)
{
printf("socket error!\n");
return -1;
}
tSocketServerAddr.sin_family = AF_INET; // 地址族 IPv4 Internet
tSocketServerAddr.sin_port = htons(SERVER_PORT); // 主机字节序转换为网络字节序 host to net, short
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY; // 所有地址 0.0.0.0
memset(tSocketServerAddr.sin_zero, 0, 8); // 清零,不使用
/* 2.通过文件描述符绑定Server端套接字的IP地址和端口。 */
iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
{
if(-1 == iRet)
{
printf("bind error!\n");
return -1;
}
}
/* 3.创建监听队列,并将 bind 的文件描述符变为监听套接字。 */
iRet = listen(iSocketServer, BACKLOG);
if(-1 == iRet)
{
printf("listen error!\n");
return -1;
}
while(1)
{
iAddrLen = sizeof(struct sockaddr);
/* 4.获得连接请求,并且建立连接。每处理一个连接,则 accept 返回该连接对应的套接字描述符。如果该队列为空,则 accept 阻塞。 */
iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
if(-1 != iSocketClient)
{
// inet_ntoa 将网络地址转换成“.”点隔的字符串格式
printf("Get Connect From Client %d : %s\n", ++iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));
if(!fork()) // 创建子进程
{
while(1)
{
/* 5.recv接收 TCP 连接的对端发送来的数据,返回值是实际读到的字节数。 */
iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
if(iRecvLen <= 0)
{
close(iSocketClient);
return -1;
}
else
{
// 数组结尾加'\0'转换为字符数组
ucRecvBuf[iRecvLen] = '\0';
printf("Get Msg From Client %d : %s\n", iClientNum, ucRecvBuf);
}
}
}
}
}
close(iSocketServer);
return 0;
}
三、client程序
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
/* socket
* connect
* send/recv
*/
#define SERVER_PORT 8888 //Server端口
int main(int argc, char **argv)
{
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
int iRet;
unsigned char ucSendBuf[1000];
int iSendLen;
if(argc != 2)
{
printf("Usage: %s <server_ip>\n", argv[0]);
return -1;
}
/* 1.创建Client端套接字,AF_INET表明地址族 IPv4 Internet,SOCK_STREAM表明使用 TCP 协议,返回文件描述符。 */
iSocketClient = socket(AF_INET, SOCK_STREAM, 0);
tSocketServerAddr.sin_family = AF_INET; // 地址族 IPv4 Internet
tSocketServerAddr.sin_port = htons(SERVER_PORT); // 主机字节序转换为网络字节序 host to net, short
//tSocketServerAddr.sin_addr.s_addr = INADDR_ANY; // 所有地址 0.0.0.0
if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
{
printf("invalid server_ip!\n");
return -1;
}
memset(tSocketServerAddr.sin_zero, 0, 8); // 清零,不使用
/* 2.connect一般由客户端程序执行,需要指定连接的服务器端的 IP 地址和端口。该方法执行后,会进行三次握手,建立连接。 */
iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if(-1 == iRet)
{
printf("connect error!\n");
return -1;
}
while(1)
{
if(fgets(ucSendBuf, 999, stdin))
{
/* 3.send用来向 TCP/UDP 连接的对端发送数据。 */
iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
if(iSendLen <= 0)
{
close(iSocketClient);
return -1;
}
}
}
return 0;
}
四、相关文章