/*
先看TCP服务器端的程序:
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 10000
int main(int argc, char *argv[])
{
int sockfd,new_fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size;
int nbytes;
char buffer[1024];
/* 服务器端开始建立sockfd描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"Socket error:%s\n\a",strerror(errno));
exit(1);
}
/* 服务器端填充 sockaddr结构 */
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(PORT);
/* 捆绑sockfd描述符到IP地址 */
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"Bind error:%s\n\a",strerror(errno));
exit(1);
}
/* 设置允许连接的最大客户端数 */
if(listen(sockfd,5)==-1)
{
fprintf(stderr,"Listen error:%s\n\a",strerror(errno));
exit(1);
}
while(1)
{
/* 服务器阻塞,直到客户程序建立连接 */
memset(buffer, '\0', sizeof(buffer));
sin_size=sizeof(struct sockaddr_in);
if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1)
{
fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
exit(1);
}
fprintf(stderr,"Server get connection from %s\n",inet_ntoa(client_addr.sin_addr));
if((nbytes=read(new_fd,buffer,1024))==-1)
{
fprintf(stderr,"Read Error:%s\n",strerror(errno));
exit(1);
}
buffer[nbytes]='\0';
printf("Server received %s\n",buffer);
}
/* 结束通讯 */
close(sockfd);
exit(0);
}
</pre><pre code_snippet_id="360375" snippet_file_name="blog_20140523_3_143696" name="code" class="html">/*
再看客户端的程序:
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 10000
int main(int argc, char *argv[])
{
int sockfd;
char buffer[1024] = "hello";
struct sockaddr_in server_addr;
/* 客户程序开始建立 sockfd描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
exit(1);
}
/* 客户程序填充服务端的资料 */
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(PORT);
inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);
again:
/* 客户程序发起连接请求 */
if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));
goto again;
}
if(write(sockfd,buffer,strlen(buffer)) <= 0)
{
<span style="white-space:pre"> </span>goto again;
}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return 0;
}
说明:
inet_ntoa用法如下:
- char *inet_ntoa(struct in_addr in);
- struct in_addr{
- unsigned long s_addr;
- }
- struct sockaddr_in {
- short int sin_family;
- unsigned short int sin_port;
- struct in_addr sin_addr;
- unsigned char sin_zero[8];
- };
在服务器端使用accept函数之后,会得到客户端连接的struct sockaddr结构,然后将其转换成struct sockaddr_in结构,此时可以在服务器端得到客户端连接的IP和端口数据。
这时用这个函数有一个问题是:如果在64位的机器上,使用
- char* tmp = inet_ntoa(sin->sin_addr);
在网上找的两种解决办法:
- 在使用的文件中,引用#include <arpa/inet.h>头文件。
- 直接使用inet_ntop函数。
inet_ntop的说明如下:
- NAME
- inet_ntop - Parse network address structures
- SYNOPSIS
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- const char *inet_ntop(int af, const void *src,
- char *dst, socklen_t cnt);
- DESCRIPTION
- This function converts the network address structure src in the af address family into a char-
- acter string, which is copied to a character buffer dst, which is cnt bytes long.
- inet_ntop(3) extends the inet_ntoa(3) function to support multiple address families,
- inet_ntoa(3) is now considered to be deprecated in favor of inet_ntop(3). The following
- address families are currently supported:
- AF_INET
- src points to a struct in_addr (network byte order format) which is converted to an IPv4
- network address in the dotted-quad format, "ddd.ddd.ddd.ddd". The buffer dst must be at
- least INET_ADDRSTRLEN bytes long.
- AF_INET6
- src points to a struct in6_addr (network byte order format) which is converted to a rep-
- resentation of this address in the most appropriate IPv6 network address format for this
- address. The buffer dst must be at least INET6_ADDRSTRLEN bytes long.
- RETURN VALUE
- inet_ntop() returns a non-null pointer to dst. NULL is returned if there was an error, with
- errno set to EAFNOSUPPORT if af was not set to a valid address family, or to ENOSPC if the con-
- verted address string would exceed the size of dst given by the cnt argument.
- CONFORMING TO
- POSIX.1-2001. Note that RFC 2553 defines a prototype where the last parameter cnt is of type
- size_t. Many systems follow RFC 2553. Glibc 2.0 and 2.1 have size_t, but 2.2 has socklen_t.
因此修改为:
char IPdes[16]="";
inet_ntop(AF_INET, (void *)&client_addr.sin_addr, IPdes, 16);
fprintf(stderr,"Server get connection from %s\n",IPdes);