如何基于C语言socket编程实现TCP通信

TCP/IP协议(Transmission Control Protocol/Internet Protocol)叫做传输控制/网际协议,又叫网络通信协议。实际上,它包含上百个功能的协议,如ICMP(互联网控制信息协议)、FTP(文件传输协议)、UDP(用户数据包协议)、ARP(地址解析协议)等。TCP负责发现传输的问题,一旦有问题就会发出重传信号,直到所有数据安全正确的传输到目的地。

套接字(socket):在网络中用来描述计算机中不同程序与其他计算机程序的通信方式。socket其实是一种特殊的IO借口,也是一种文件描述符。

套接字分为三类:

流式socket(SOCK_STREAM):流式套接字提供可靠、面向连接的通信流;它使用TCP协议,从而保证了数据传输的正确性和顺序性。

数据报socket(SOCK_DGRAM):数据报套接字定义了一种无连接的服务,数据通过相互独立的保温进行传输,是无序的,并且不保证是可靠、无差错的。它使用的数据报协议是UDP。

原始socket:原始套接字允许对底层协议如IP或ICMP进行直接访问,它功能强大但使用复杂,主要用于一些协议的开发。

套接字由三个参数构成:IP地址,端口号,传输层协议。

这三个参数用以区分不同应用程序进程间的网络通信与连接。

套接字的数据结构:C语言进行套接字编程时,常会使用到sockaddr数据类型和sockaddr_in数据类型,用于保存套接字信息。

两种结构体分别表示如下:

struct sockaddr
{
  //地址族,2字节
  unsigned short sa_family;
  //存放地址和端口,14字节
  char sa_data[14];
}

struct sockaddr_in
{
  //地址族
  short int sin_family;
  //端口号(使用网络字节序)
  unsigned short int sin_port;
  //地址
  struct in_addr sin_addr;
  //8字节数组,全为0,该字节数组的作用只是为了让两种数据结构大小相同而保留的空字节
  unsigned char sin_zero[8]
}

对于sockaddr,大部分的情况下只是用于bind,connect,recvfrom,sendto等函数的参数,指明地址信息,在一般编程中,并不对此结构体直接操作。而是用sockaddr_in来代替。

两种数据结构中,地址族都占2个字节,常见的地址族有:AF_INET,AF_INET6,AF_LOCAL。

这里要注意字节序的问题,最好使用以下函数来对端口和地址进行处理:

uint16_t htons(uint16_t host16bit) uint32_t htonl(uint32_t host32bit)
uint16_t ntohs(uint16_t net16bit) uint32_t ntohs(uint32_t net32bit)

将主机字节序改成网络字节序。

使用socket进行TCP通信时,经常使用的函数有:

下面是TCP通信的demo:

/*socket tcp服务器端*/
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define SERVER_PORT 5555

/*
 监听后,一直处于accept阻塞状态,
 直到有客户端连接,
 当客户端如数quit后,断开与客户端的连接
 */

int main()
{
  //调用socket函数返回的文件描述符
	int serverSocket;
  //声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器
	struct sockaddr_in server_addr;
	struct sockaddr_in clientAddr;
	int addr_len = sizeof(clientAddr);
	int client;
	char buffer[200];
	int iDataNum;

  //socket函数,失败返回-1
  //int socket(int domain, int type, int protocol);
  //第一个参数表示使用的地址类型,一般都是ipv4,AF_INET
  //第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM
  //第三个参数设置为0
	if((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("socket");
		return 1;
	}

	bzero(&server_addr, sizeof(server_addr));
  //初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(SERVER_PORT);
  //ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  //对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)
  //bind三个参数:服务器端的套接字的文件描述符,
  if(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
	{
		perror("connect");
		return 1;
	}
  //设置服务器上的socket为监听状态
	if(listen(serverSocket, 5) < 0)
	{
		perror("listen");
		return 1;
	}

	while(1)
	{
		printf("Listening on port: %d\n", SERVER_PORT);
    //调用accept函数后,会进入阻塞状态
    //accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,
    //serverSocket和client。
    //serverSocket仍然继续在监听状态,client则负责接收和发送数据
    //clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号
    //addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。
    //传出的是客户端地址结构体的实际长度。
    //出错返回-1
		client = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
		if(client < 0)
		{
			perror("accept");
			continue;
		}
		printf("\nrecv client data...n");
    //inet_ntoa  ip地址转换函数,将网络字节序IP转换为点分十进制IP
    //表达式:char *inet_ntoa (struct in_addr);
		printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));
		printf("Port is %d\n", htons(clientAddr.sin_port));
		while(1)
		{
			iDataNum = recv(client, buffer, 1024, 0);
			if(iDataNum < 0)
			{
				perror("recv");
				continue;
			}
			buffer[iDataNum] = '\0';
			if(strcmp(buffer, "quit") == 0)
				break;
			printf("%drecv data is %s\n", iDataNum, buffer);
			send(client, buffer, iDataNum, 0);
		}
	}
	return 0;
}
/*socket tcp客户端*/
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define SERVER_PORT 5555

/*
 连接到服务器后,会不停循环,等待输入,
 输入quit后,断开与服务器的连接
 */

int main()
{
  //客户端只需要一个套接字文件描述符,用于和服务器通信
	int clientSocket;
  //描述服务器的socket
	struct sockaddr_in serverAddr;
	char sendbuf[200];
	char recvbuf[200];
	int iDataNum;
	if((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("socket");
		return 1;
	}

	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(SERVER_PORT);
  //指定服务器端的ip,本地测试:127.0.0.1
  //inet_addr()函数,将点分十进制IP转换成网络字节序IP
	serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	if(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
	{
		perror("connect");
		return 1;
	}

	printf("connect with destination host...\n");

	while(1)
	{
		printf("Input your world:>");
		scanf("%s", sendbuf);
		printf("\n");

		send(clientSocket, sendbuf, strlen(sendbuf), 0);
		if(strcmp(sendbuf, "quit") == 0)
			break;
		iDataNum = recv(clientSocket, recvbuf, 200, 0);
		recvbuf[iDataNum] = '\0';
		printf("recv data of my world is: %s\n", recvbuf);
	}
	close(clientSocket);
	return 0;
}
(0)

相关推荐

  • socket多人聊天程序C语言版(二)

    socket多人聊天程序C语言版(一)地址: http://www.jb51.net/article/94938.htm 1V1实现了,1V多也就容易了.不过相对于1V1的程序,我经过大改,采用链表来动态管理.这样效率真的提升不少,至少CPU使用率稳稳的在20以下,不会飙到100了.用C语言写这个还是挺费时间的,因为什么功能函数都要自己写,不像C++有STL库可以用,MFC写就更简单了,接下来我还会更新MFC版本的多人聊天程序.好了,废话少说,进入主题. 这个程序要解决的问题如下: 1.CPU使

  • C语言编写基于TCP和UDP协议的Socket通信程序示例

    Tcp多线程服务器和客户端程序 服务器程序: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #define PORT 8082 #define BUFSIZE 512 cha

  • 使用C语言编写基于TCP协议的Socket通讯程序实例分享

    tcp客户端示例 #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <stdio.h> #include <unistd.h>

  • socket多人聊天程序C语言版(一)

    首先,不要一步登天直接解决多人聊天这个问题,先把问题化简. 1.多人聊天的核心问题是服务器如何标识不同的客户端,如何根据客户端的需求转发消息给指定客户端. 2.多人聊天转化为C-C聊天,但是不再是直接C-C,而是通过server转发消息,所以变成==>C-S-C. 3.server如何允许2个client同时连接,设置listen函数的第二个参数,最大连接数. 4.server如何标识两个client,用一个结构体数组来存放两个client的信息. 5.server如何转发消息给client,很

  • 如何基于C语言socket编程实现TCP通信

    TCP/IP协议(Transmission Control Protocol/Internet Protocol)叫做传输控制/网际协议,又叫网络通信协议.实际上,它包含上百个功能的协议,如ICMP(互联网控制信息协议).FTP(文件传输协议).UDP(用户数据包协议).ARP(地址解析协议)等.TCP负责发现传输的问题,一旦有问题就会发出重传信号,直到所有数据安全正确的传输到目的地. 套接字(socket):在网络中用来描述计算机中不同程序与其他计算机程序的通信方式.socket其实是一种特殊

  • 基于C#的socket编程的TCP异步的实现代码

    一.摘要 本篇阐述基于TCP通信协议的异步实现. 二.实验平台 Visual Studio 2010 三.异步通信实现原理及常用方法 3.1 建立连接 在同步模式中,在服务器上使用Accept方法接入连接请求,而在客户端则使用Connect方法来连接服务器.相对地,在异步模式下,服务器可以使用BeginAccept方法和EndAccept方法来完成连接到客户端的任务,在客户端则通过BeginConnect方法和EndConnect方法来实现与服务器的连接. BeginAccept在异步方式下传入

  • java实现基于TCP协议网络socket编程(C/S通信)

    一.前言:TCP原理简介 首先,保证文章完整性,TCP的理论原理还是需要简介一下,略显枯燥๑乛◡乛๑. TCP(传输控制协议,Transmission Control Protocol)是一种面向连接的.可靠的.基于字节流的传输层通信协议.TCP旨在适应支持多网络应用的分层协议层次结构.也就是说,TCP是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议. 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务. 以上TCP的特点,也正是与UD

  • java实现基于UDP协议网络Socket编程(C/S通信)

    一.前言:认识UDP UDP,全称User Datagram Protocol(用户数据报协议),是Internet 协议集支持一个无连接的传输协议.UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法. UDP主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成,提供面向报文的简单不可靠信息传送服务.UDP 协议基本上是IP协议与上层协议的接口,适用端口分别运行在同一台设备上的多个应用程序. 二.UDP的特点(与TCP相比) 正是UDP提供不可靠服务

  • Java多线程实现TCP网络Socket编程(C/S通信)

    开篇必知必会 在前一篇<基于TCP协议网络socket编程(java实现C/S通信)>,实际存在一个问题,如果服务器端在建立连接后发送多条信息给客户端,客户端是无法全部接收的,原因在于客户端为单线程,只接受了第一条信息,剩余信息阻塞等待下一次发送.所以,这造成了客户端无法处理消息队列,每次只接收并输出一条服务器信息,出现信息不同步问题. 本篇将解决这个问题,详细记录实现java多线程通信,目标是使客户端可以一次接收服务器发送的多条信息,避免阻塞.方法是将客户端接收信息功能独立为一个线程来完成,

  • 基于Java实现Socket编程入门

    目录 认识Socket 建立socket的基本流程 1.最基本的Socket示范 1.1单向通信 1.2双向通信 2.发送更多的消息:结束的界定 2.1使用特殊符号 2.2根据长度界定 3.处理更多的连接:多线程 3.1同时实现消息的发送与接收 3.2使用线程池优化服务端并发能力 4.连接保活 4.1使用心跳包 4.2断开时重连 认识Socket socket,又称套接字,是在不同的进程间进行网络通讯的一种协议.约定或者说是规范. 对于socket编程,它更多的时候像是基于TCP/UDP等协议做

  • Qt网络编程实现TCP通信

    Qt网络编程实现TCP通信,供大家参考,具体内容如下 标签(空格分隔): Tcp通信 一.Tcp简介 (1)TCP(Transmission Control Protocol,传输控制协议)TCP是一个用于数据传输的传输层网络协议,多个网络协议包括(HTTP和FTP都是基于TCP协议),TCP是面向数据流和连接的可靠的传输协议,它区别于传输层的另外一个协议UDP(具体可看—Qt简单实现UDP通信) . (2)QTcpSocket继承自QAbstractSocket,与QUdpSocket传输的数

  • C语言socket编程开发应用示例

    实现步骤: 1. Server端 复制代码 代码如下: #include <stdio.h>                   //用于printf等函数的调用#include <winsock2.h>                //Socket的函数调用 #pragma comment (lib, "ws2_32")      //C语言引用其他类库时,除了.h文件外,还要加入对应的lib文件(这个不同于C#) 复制代码 代码如下: int main()

  • C语言中的socket编程实例代码

    前不久刚看完<c primer plus>,收获颇丰,对于C语言也有了更全面的认识,对于模块化和数据结构也有了更多的想法,之前学过C语言,但很多已经记不起了,知识很零散,这也是我看这本书的原因. 之后一段时间都会在进一步学习编程的同时研究socket通讯,目标是要将socket研究透,设计出自己的框架,以后从事服务器开发和构架应该也会大有裨益. 好了,废话不多说,奉上网上找的源码. /* window socket 服务端编程测试 */ #include <stdio.h> //用

  • Java基于Tcp协议的socket编程实例

    本文实例讲述了Java基于Tcp协议的socket编程方法,分享给大家供大家参考.具体分析如下: 以下是一对一的通信编程实现,后续会继续学习一个服务器监听多个客户端的实现. 这里用到的主要步骤如下: 第一步:以特定端口(如4800)新建socket对象 第二步:以系统输入设备构造BufferedReader对象,该对象用于接收系统键盘输入的字符 第三步:以socket对象 得到输出流来构造PrintWriter 第四步:以socket对象得到输入流来构造相应的BufferedReader对象,该

随机推荐