sever
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
/* socket
* bind
* listen
* accept
* send/recv
*/
#define SERVER_PORT 8888
#define BACKLOG 10
int main(int argc, char **argv)
{
int iSocketServer;
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
struct sockaddr_in tSocketClientAddr;
int iRet;
int iAddrLen;
int iRecvLen;
unsigned char ucRecvBuf[1000];
int iClientNum = -1;
//0、子进程关闭僵死解决函数
signal(SIGCHLD,SIG_IGN);
/*1、 socket(domain, type,protocol ):
domain 指定套接字的协议族 常见AF_INET(IPv4)和AF_INET6(IPv6);
type:指定套接字的类型,常见的有SOCK_STREAM(流式套接字,用于TCP协议)和SOCK_DGRAM(数据报套接字,用于UDP协议)
protocol:指定套接字所使用的协议,通常为0 */
iSocketServer = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == iSocketServer)
{
printf("socket error!\n");
return -1;
}
/*2、初始化bind地址结构体
两种结构体一样大小,sockaddr_in为sockaddr的数据进一步分析
struct sockaddr{
unisgned short as_family;
char sa_data[14];
};
struct sockaddr_in{
unsigned short sin_family;sin_family 一般为 AF_INET(ipv4)
unsigned short sin_port;
struct in_addr sin_addr; sin_addr 设置为 INADDR_ANY 表示可以和任何的主机通信
unsigned char sin_zero[8];
}
*/
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
memset(tSocketServerAddr.sin_zero, 0, 8);
/* 3、int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
sockfd:套接字描述符,即通过socket函数创建的套接字
addr:指向要绑定的本地地址的指针,通常是一个struct sockaddr类型的结构体指针(IP 端口)
addrlen:本地地址的长度,即addr指向的结构体的大小
*/
iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (-1 == iRet)
{
printf("bind error!\n");
return -1;
}
//4、listen(监听IP端口),BACKLOG为同时监听的路数
iRet = listen(iSocketServer, BACKLOG);
if (-1 == iRet)
{
printf("listen error!\n");
return -1;
}
while (1)
{
iAddrLen = sizeof(struct sockaddr);
//5、等待client的连接,把client的地址信息保存在tSocketClientAddr,注意第三个参数是地址长度的指针
iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
if (-1 != iSocketClient)
{
iClientNum++;
printf("Get connect from client %d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));
/*6、每来一个连接,都创建一个进程,注意这里是复制出另一个进程,
新创建的进程执行if函数体,原来的进程不执行if函数体*/
if (!fork())
{
/* 子进程的源码 */
while (1)
{
/* 7、接收客户端发来的数据并显示出来
recv(sockfd, buf, len, flags)
flag : 0:默认标志位,表示普通的阻塞式接收操作。
MSG_DONTWAIT:非阻塞模式,即使没有数据可接收也会立即返回。
MSG_PEEK:查看数据,但不从缓冲区中移除数据。
*/
iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
if (iRecvLen <= 0)
{
close(iSocketClient);
return -1;
}
else
{
ucRecvBuf[iRecvLen] = '\0';
printf("Get Msg From Client %d: %s\n", iClientNum, ucRecvBuf);
}
}
}
}
}
close(iSocketServer);
return 0;
}
client
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
/* socket
* connect
* send/recv
*/
#define SERVER_PORT 8888
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:\n");
printf("%s <server_ip>\n", argv[0]);
return -1;
}
iSocketClient = socket(AF_INET, SOCK_STREAM, 0);
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
//tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
{
printf("invalid server_ip\n");
return -1;
}
memset(tSocketServerAddr.sin_zero, 0, 8);
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))
{
iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
if (iSendLen <= 0)
{
close(iSocketClient);
return -1;
}
}
}
return 0;
}