基于tcp协议的网络程序
1.所用函数:
socket函数
- socket()打开一个网络端口,如果成功,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上首发数据,如果调用出错返回-1
bind函数:
- 服务器程序所监听的网络地址和端口号通常是固定不变得,客户端程序得知服务器程序的地址和端口后就可以向服务器发起连接,因此需要调用bind()绑定一个固定的网络地址和端口号`.bind函数的作用是将参数sockfd和myaddr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听myaddr所描述的地址和端口号。
bind()成功是返回0,失败返回-1
listen()函数
listen()函数的作用是将套接字的状态设置为监听状态,即检测新的客户是否到来的状态
accept()函数
connect()函数
- 客户端需要调用connect()连接服务器,connect()bind()的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址
成功返回0,失败返回-1
由于本节基于IPv4的socket网络编程,sockaddr_in中的成员struct in_addr sin_addr表示32位的IP地址。但是我们通常用点分十进制的字符串表示IP地址,以下函数可以在字符串表示和in _addr表示之间转换。
字符串转in_addr
in_addr转字符串
2.tcp_server.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<string.h>
#include <netinet/in.h>
static void usage(const char* proc)
{
printf("Usage:%s [local_ip] [local_port]\n",proc);
}
int startup(const char* _ip,int _port)
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0 )
{
perror("socket");
exit(2);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(_port);
local.sin_addr.s_addr = inet_addr(_ip);
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
perror("bind");
exit(3);
}
if(listen(sock,10) < 0)
{
perror("listen");
exit(4);
}
return sock;
}
//./tcp_server ip port
int main(int argc,char* argv[] )
{
if(argc!=3)
{
usage(argv[0]);
return 1;
}
while(1)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int listen_sock = startup(argv[1],atoi(argv[2]));
int new_sock = accept(listen_sock,(struct sockaddr*)&client,&len);
if(new_sock<0)
{
perror("acc");
continue;
}
printf("get a new client ,%s:%d\n",inet_ntoa(client.sin_addr),\
ntohs(client.sin_port));
while(1)
{
char buf[1024];
ssize_t s= read(new_sock,buf,sizeof(buf)-1);
if(s>0)
{
buf[s]=0;
printf("client: %s\n",buf);
write(new_sock,buf,strlen(buf));
}
else if(s==0)
{
close(new_sock);
printf("client is quit\n");
break;
}
else
{
perror("read");
exit(5);
}
}
}
}
3.tcp_client.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<string.h>
static void usage(const char* proc)
{
printf("Usage:%s [local_ip] [local_port]\n",proc);
}
//tcp_client server_ip server_port
int main(int argc,char* argv[])
{
if(argc!=3)
{
usage(argv[0]);
return 1;
}
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0 )
{
perror("socket");
exit(2);
}
struct sockaddr_in server_sock;
server_sock.sin_family = AF_INET;
server_sock.sin_port = htons(atoi(argv[2]));
server_sock.sin_addr.s_addr = inet_addr(argv[1]);
if(connect(sock,(struct sockaddr*)&server_sock,sizeof(server_sock))<0)
{
printf("connect failed ");
exit(3);
}
printf("connect success\n");
char buf[1024];
while(1)
{
printf("Please Enter#");
fflush(stdout);
ssize_t s=read(0,buf,sizeof(buf)-1);
if(s>0)
{
buf[s-1]=0;
write(sock,buf,strlen(buf));
s = read(sock,buf,sizeof(buf)-1);
if(s>0)
{
buf[s] = 0;
printf("server ehco:%s\n ",buf);
}
}
}
}
运行:
- 输入指令 >ifconfig 查看本机的ip地址为下图:
- 输入>./tcp_server.c 192.168.1.103 8080 运行服务器端。
- 同时再开一个终端输入> >./tcp_client.c 192.168.1.103 8080 运行客户端。
- 接下来在客户端给服务器端发消息,同时从客户端可以收到来自服务器端的回应,如下图: